datenum() #@ Convert DATE to day NUMBER in C.E.
{ #@ USAGE: datenum [DATE [VAR]]
local _y _m _d junk var num base=-306 ymd _dn
local invalid="Invalid date" jg_m=175209 j2g_skip=11
local j2g='Invalid date (Julian to Gregorian changeover)'
[[ $1 == -- ]] && shift
if (( $# == 0 )) || is_var "$1"
then
today ymd
elif is_date "$1"
then
ymd=$1
is_var "$2"
else
err 1 "$invalid: $1" || return
fi
read _y _m _d junk <<< "${ymd//[!0-9]/ }"
if [[ $_y == [0-9][0-9][0-9][0-9][0-1][0-9][0-3][0-9] ]]
then
_d=${_y: -2}
_m=${_y:4:2}
_y=${_y:0:4}
fi
_d=${_d#0}
_m=${_m#0}
_m=$((12 * _y + _m - 3)) ## Calculate number of months from March
_y=$(( _m / 12)) ## and adjust year if necessary
_ly=$(( _y/4-_y/100+_y/400 )) ## number of leap days
_dn=$(( (734 * _m + 15) / 24 - 2 * _y + _ly + _d + base ))
if [[ $_dn -ge 639786 && $_dn -le 639795 ]]
then ## date was swallowed by Julian to Gregorian changeover
err 1 "$j2g" || return
elif [[ $_dn -lt 1 ]]
then
err 2 "$invalid $ymd" || return
fi
(( _dn > 639796 )) && _dn=$(( _dn - j2g_skip ))
[[ $var ]] && printf -v "$var" %d "$_dn" || printf '%s\n' "$_dn"
}
The datenum
function can be called in four different
ways:
- datenum
- datenum VAR
- datenum DATE
- datenum DATE VAR
The date, if supplied, must be in the ISO format:
YYYY-MM-DD
, though there is some lattitude.
Any non-numeric separator may be used, and leading zeroes may be
omitted.
If no date is supplied, the current date is used.
If no variable name is supplied, the result is printed
to stdout
.
The function is valid from 1-01-01 (using the Julian calendar until the changover to Gregorian in September 1752) until long after the sun explodes (or until the Gregorian calendar is replaced by some other system).