From 431473c45813ba9beb15d123d119fcb1dcd0a97c Mon Sep 17 00:00:00 2001 From: Patrick McDermott Date: Sat, 15 Jun 2019 20:44:32 -0400 Subject: lib/time.sh: New file --- (limited to 'lib/time.sh') diff --git a/lib/time.sh b/lib/time.sh new file mode 100644 index 0000000..b65bbba --- /dev/null +++ b/lib/time.sh @@ -0,0 +1,162 @@ +# 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 +} + +## @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() 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 hour= + local min= + local sec= + local tz= + local tzsgn= + local tzhour= + local tzmin= + + read wday mday mon year hour min sec tz <<-EOF + ${rfc822_tm} + EOF + tzsgn="${tz%%[0-9]*}"; tz=${tz#[+-]}; tz=${tz#0}; tz=${tz#0} + tzhour=$((${tz} / 100)) + tzmin=$(( ${tz} % 100)) + _ob_mktime ${year} ${mon#0} ${mday#0} ${hour#0} ${min#0} ${sec#0} \ + $((${tzsgn}1 * (${tzhour} * 60 + ${tzmin}) * 60)) + 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 +## 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 + 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} -gt $(_ob_month_to_days $((${mon} + 1)) ${year}) ]; do + : $((mon += 1)) + done + mday=$((${timep} - $(_ob_month_to_days ${mon} ${year}) + 1)) + + printf '%04d-%02d-%02dT%02d:%02d:%02dZ' \ + ${year} ${mon} ${mday} ${hour} ${min} ${sec} + return 0 +} -- cgit v0.9.1