Skip to content

Instantly share code, notes, and snippets.

@JeffreySarnoff
Last active March 31, 2017 03:20
Show Gist options
  • Save JeffreySarnoff/4191491 to your computer and use it in GitHub Desktop.
Save JeffreySarnoff/4191491 to your computer and use it in GitHub Desktop.
still daynumbers
#=
#
# filename: DayNumber.jl
#
# part of : Time for Julia
# in part : my own software
#
# purpose : canonical daycounts for TAI dates
#
# offers : ymd_to_daynumber, daynumber_to_ymd
#
# caution : IT IS AN UNCHECKED ERROR
# to use a year not in [ -4399 .. +4399 ]
# to use daynumber not in [ +366 .. +3214133 ]
#
# language: Julia (written for ver 0.0.0 >= 2012-11-29)
# (updated for ver 0.5+ >= 2016-Jun-01)
#
# author : Jeffrey A. Sarnoff
#
# created : 2012-Jul-02 10:20 America/New_York
# edited : 2012-Dec-02 17:40 America/New_York
# updated : 2017-Mar-08 19:31 America/New_York
#
# rights : This work is available for use with Julia without restriction.
#
=#
module DayNumber
export
ymd_to_daynumber, daynumber_to_ymd
# Dates in a proleptic Gregorian calendar using year zero.
#
# daynumber_to_ymd( ymd_to_daynumber(y,m,d) ) == y,m,d
#
# exhaustively verified for all accepted dates
# in the years: [ -3999.. -1, 0, +1 ..3999 ]
# convert date into a nonnegative daynumber
# dates change at midnight (a fact not used in this function)
# months: Jan=1,..,Dec=12, days: 1..31
# supports years (-3999..,-2,-1,0,1,2,..3999)
# aligns with the Gregorian 400 year cycle (146907 days)
# multiples of 400 years have daynumber multiples of 146097
# this is true for positive and for negative years
# requires year numbered using the non-historical Year 0
# uses a non-historical proleptic Gregorian calendar
# historically, year 8 is the first year properly a leap year
#
# Notes
# to obtain the corresponding Int64 daynumber subtract 1607067
#
# ( y, m, d) --> daynumber, description
#
# ( 4400, 1, 1) --> 3214134 [ and that is the soft clopen upper bound]
# ( 4399,12,31) --> 3214133 [ and that is the soft realized upper bound]
#
# ( 3999,12,31) --> 3068036 [ exhaustively verified upper bound ]
#
# ( 1970, 1, 1) --> 2326595 [ UNIX Epoch (zero) ]
# ( 1, 1, 1) --> 1607433
# ( 0, 1, 1) --> 1607067 [ 0 + 4400 Gregorian years]
# ( -1, 1, 1) --> 1606702
#
# (-3999,12,31) --> 146827 [ exhaustively verified lower bound ]
#
# (-4399, 1, 1) --> 366 [and that is the soft lower bound]
# all intervals are clopen so do not use this as a spec:
# (-4400, 3, 1) --> 60 [and that is the hard lower bound]
#
# daynumber requires 22 bits (for this date range)
# hour,min,sec requires 17 bits (for one day)
# 39 bits (for date and time-of-day)
#
# timezone num requires 9 bits
# 48 bits (for date, time-of-day, timezone)
#
# millisecs requires 10 bits
# or year requires 13 bits
# this function with annotations is nearby eof
#
const adjust_monthdays = Int32[ 365, 396, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ];
function ymd_to_daynumber(y::Int32, m::Int32, d::Int32)
k0::Int32 = 0; k1::Int32 = 1; k2::Int32 = 2; k3::Int32 = 3
k32::Int32 = 32; k365::Int32 = 365; k4400::Int32 = 4400
k42949673::Int32 = 42949673
y = y + k4400
y = y + ifelse(m >= k3, k0, k1)
d = d + (k365 * y)
y100 = ((k42949673 * y) >> k32)
d = d + (y >> k2) - y100 + (y100 >> k2)
d = d + adjust_monthdays[m]
return d
end
ymd_to_daynumber(yr::Int64, mo::Int64, dy::Int64) =
ymd_to_daynumber(yr%Int32, mo%Int32, dy%Int32)
# this function with annotations is nearby eof
#
function daynumber_to_ymd(daynum::Int64)
K = Y = M = D = 0
daynum = daynum + 182562
K = div( (daynum<<2), 146097 )
daynum = daynum - ( (146097*K + 3) >> 2 )
Y = div( 4000*(daynum+1), 1461001 )
daynum = daynum - ( ((1461*Y) >> 2) - 31 )
M = div( (80*daynum), 2447 )
D = daynum - div( (2447*M), 80 )
daynum = div( M, 11 )
M = M + ( 2 - (12*daynum) )
Y = Y + ( (100*(K-49)) + daynum)
return Y%Int32, M%Int32, D%Int32
end
daynumber_to_ymd(daynum::Int32) =
daynumber_to_ymd( daynum%Int64 )
#>
#
# the same annotated
# my sculpting shown
#
#<
#=
function ymd_to_daynumber(y::Int32, m::Int32, d::Int32)
# if (m<3)
# y-= 1; y+=4400
# else
# y += 4400
# end
#
# )to)
#
# if (m<3) y += 4399 else y += 4400 end;
#
# )to)
y += 4400
y -= (m >= 3) ? 0 : 1
d += (365*y)
# assert(y >= 0)
# tally leap years through year y
# ( +udiv4(y) -udiv100(y) +udiv400(y) )
#
# )to)
y100 = (y * 42949673) >> 32
d += (y>>2) - y100 + (y100 >> 2)
# int64(d + monthdays[m] + (365*y) + (y >>> 2) - y100 + ((y100 >> 2) - 32)
#
# )to)
#
# d += ( div(((152*m)-2),5) with entries 13,14 folded into 1,2) - 32
# monthdays = [ 365, 396, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ]
#
# )to)
d += [ 365, 396, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 ][m]
int64(d)
end
=#
#=
this is a date-shifted version of the
the Fliegel and van Flandern code [ACM Vol 11, 1968]
function daynumber_to_ymd(daynum::Int64)
# daynum -= 2286008 # untranslate Day Number (1607067 -32 +678973)
# daynum = daynum + 2400001 + 68569
daynum += 182562
# K = div(4*daynum, 146097)-3
K = div( (daynum<<2), 146097 )
#daynum = daynum - div((146097*K + 3), 4)
daynum -= ((146097*K + 3) >> 2)
Y = div(4000*(daynum+1), 1461001)
#daynum = daynum - div(1461*Y, 4) + 31
daynum -= (((1461*Y) >> 2) - 31)
M = div(80*daynum, 2447)
D = daynum - div(2447*M,80)
daynum = div(M,11)
#M = M + 2 - 12*daynum
M += (2 - 12*daynum)
#Y = 100*(K-49) + Y + daynum
Y += 100*(K-49) + daynum
return Y%nt32, M%Int32, D%Int32
end
=#
end # module DayNumber
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment