# Functions for converting date and time # # Copyright (C) 2019 Patrick McDermott # # This file is part of opkbuild. # # opkbuild is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # opkbuild is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with opkbuild. If not, see . _ob_is_leap_year() { local year="${1}" shift 1 || _ob_abort return $((!(!(${year} % 4) && ${year} % 100 || !(${year} % 400)))) } _ob_year_to_days() { local year="${1}" shift 1 || _ob_abort local y=1970 local d=0 # Simple but iterative. while [ ${y} -ne ${year} ]; do _ob_is_leap_year ${y} && : $((d += 366)) || : $((d += 365)) : $((y += 1)) done printf '%d' ${d} return 0 } _ob_month_to_days() { local month="${1}" local year="${2}" shift 2 || _ob_abort local d= case ${month} in 1) d=0;; 2) d=31;; 3) d=59;; 4) d=90;; 5) d=120;; 6) d=151;; 7) d=181;; 8) d=212;; 9) d=243;; 10) d=273;; 11) d=304;; 12) d=334;; esac [ ${month} -ge 2 ] && _ob_is_leap_year ${year} && : $((++d)) printf '%d' ${d} return 0 } _ob_mktime() { local year="${1}" local mon="${2}" local mday="${3}" local hour="${4}" local min="${5}" local sec="${6}" local timezone="${7}" shift 7 || _ob_abort local d= local t= d=$(($(_ob_year_to_days ${year}) + $(_ob_month_to_days ${mon} ${year}))) d=$((${d} + ${mday} - 1)) t=$(( ( (${d} * 24 + ${hour}) * 60 + ${min}) * 60 + ${sec} )) t=$((${t} - ${timezone})) printf '%d' ${t} return 0 } _ob_mon_to_m() { local mon="${1}" shift 1 || _ob_abort local m= case ${mon} in Jan) m=1;; Feb) m=2;; Mar) m=3;; Apr) m=4;; May) m=5;; Jun) m=6;; Jul) m=7;; Aug) m=8;; Sep) m=9;; Oct) m=10;; Nov) m=11;; Dec) m=12;; esac printf '%d' ${m} return 0 } ## @brief Convert a date and time into seconds since the Epoch ## @details \fBob_rfc822_mktime\fP() converts date and time formatted according ## to RFCs 822, 2822, and 5322 into non-leap seconds elapsed since the ## Epoch. It is similar to the C function \fBmktime\fP(3) except that ## it accepts a formatted string instead of a structure as its ## argument. It is intended to parse \fIchangelog\fP dates into a time ## value usable in the \fISOURCE_DATE_EPOCH\fP environment variable. ## @operand rfc822_tm req A date and time string formatted according to the ## \fIdate-time\fP symbol of RFC 5322 section 3.3. ## @return Returns 0. ## @stdout Prints the number of non-leap seconds elapsed since the Epoch. ## @pure yes This function has no side effects. ob_rfc822_mktime() { local rfc822_tm="${1}" shift 1 || _ob_abort local wday= local mday= local mon= local year= local time= local tz= local hour= local min= local sec= local tzsgn= local tzhour= local tzmin= read wday mday mon year time tz <<-EOF ${rfc822_tm} EOF mon=$(_ob_mon_to_m ${mon}) IFS=':' read hour min sec <<-EOF ${time} EOF tzsgn="${tz%%[0-9]*}"; tzsgn="${tzsgn#+}" tz=${tz#[+-]}; tz=${tz#0}; tz=${tz#0} tzhour=$((${tz} / 100)) tzmin=$(( ${tz} % 100)) _ob_mktime ${year} ${mon} ${mday#0} ${hour#0} ${min#0} ${sec#0} \ $((${tzsgn}1 * (${tzhour} * 60 + ${tzmin}) * 60)) return 0 } _ob_gmtime() { local timep="${1}" shift 1 || _ob_abort local sec= local min= local hour= local days_in_year= local year=1970 local mon=1 local mday= sec=$((${timep} % 60)); : $((timep /= 60)) min=$((${timep} % 60)); : $((timep /= 60)) hour=$((${timep} % 24)); : $((timep /= 24)) while :; do _ob_is_leap_year ${year} && days_in_year=366 || days_in_year=365 [ ${timep} -le ${days_in_year} ] && break : $((timep -= ${days_in_year})) : $((year += 1)) done while [ ${timep} -ge $(_ob_month_to_days $((${mon} + 1)) ${year}) ]; do : $((mon += 1)) done mday=$((${timep} - $(_ob_month_to_days ${mon} ${year}) + 1)) printf '%d %d %d %d %d %d' \ ${year} ${mon} ${mday} ${hour} ${min} ${sec} return 0 } ## @brief Convert seconds since the Epoch into a date and time ## @details \fBob_iso8601_gmtime\fP() converts the number of non-leap seconds ## elapsed since the Epoch into date and time in UTC formatted ## according to ISO 8601. It is similar to the C function ## \fBgmtime\fP(3) except that it returns a formatted string instead of ## a structure. It is intended to generate a date and time usable with ## a POSIX-conformant \fBtouch\fP utility. ## @operand timep req The number of non-leap seconds elapsed since the Epoch. ## @return Returns 0. ## @stdout Prints the date and time in UTC formatted according to ISO 8601. ## @pure yes This function has no side effects. ob_iso8601_gmtime() { local timep="${1}" shift 1 || _ob_abort printf '%04d-%02d-%02dT%02d:%02d:%02dZ' $(_ob_gmtime "${timep}") return 0 } ## @brief Convert seconds since the Epoch into a date and time ## @details \fBob_touch_t_gmtime\fP() converts the number of non-leap seconds ## elapsed since the Epoch into date and time in UTC formatted for the ## \fB-t\fP option of the \fBtouch\fP utility according to POSIX. It ## is similar to the C function \fBgmtime\fP(3) except that it returns ## a formatted string instead of a structure. ## @operand timep req The number of non-leap seconds elapsed since the Epoch. ## @return Returns 0. ## @stdout Prints the date and time in UTC formatted for the \fBtouch\fP ## utility's \fB-t\fP option. ## @pure yes This function has no side effects. ob_touch_t_gmtime() { local timep="${1}" shift 1 || _ob_abort # [[CC]YY]MMDDhhmm[.SS] printf '%04d%02d%02d%02d%02d.%02d' $(_ob_gmtime "${timep}") return 0 }