Created
April 8, 2011 18:21
-
-
Save pilotmoon/910427 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file contains functions to handle conversion between Julian Day Number (JDN) and | |
# Julian and Gregorian dates. These algorithms are optimised for readability | |
# and non-repetition of code, rather than speed. | |
# | |
# Benchmark results for 500_000 runs on my machine: | |
# user system total real | |
# jdn_to_gregorian_direct 2.930000 0.020000 2.950000 ( 2.984025) | |
# jdn_to_gregorian 3.590000 0.020000 3.610000 ( 3.636085) | |
# jdn_to_julian 3.110000 0.020000 3.130000 ( 3.175516) | |
# user system total real | |
# julian_to_jdn 1.520000 0.010000 1.530000 ( 1.562086) | |
# gregorian_to_jdn 1.840000 0.010000 1.850000 ( 1.901677) | |
# | |
# Calculate the Julian Day Number at noon on a given Julian date. | |
# The parameters are assumed to be a valid Julian date. | |
def julian_to_jdn(year,month,day) | |
to_jdn(year,month,day) { |y| -32083 } | |
end | |
# Calculate the Julian Day Number at noon on a given Gregorian date. | |
# The parameters are assumed to be a valid Gregorian date. | |
def gregorian_to_jdn(year,month,day) | |
to_jdn(year,month,day) { |y| (y/400)-(y/100)-32045 } | |
end | |
# Calculate the Julian date on which a given Julian Day Number begins. | |
def jdn_to_julian(jdn) | |
# days since -4800,3,1 | |
j=jdn+32082 | |
to_date(j/36525, j%36525) | |
end | |
# Calculate the Gregorian date on which a given Julian Day Number begins. | |
def jdn_to_gregorian(jdn) | |
# days since -4800,3,1 | |
j=jdn+32044 | |
# whole quadricentennials | |
g=j/146097 | |
# remainder days in quadricentennial | |
dg=j%146097 | |
# whole centuries | |
c=REDUCE[dg/36524] | |
# finish off | |
to_date(g*4+c, dg-c*36524) | |
end | |
private | |
# Days in year so far, at start of month. Month 0=March. | |
# An altervative to using this array is to use (153*m+2)/5. | |
MDAY=[0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337] | |
# Reduce 4 to 3, leave 0..3 the same. | |
# Could do x>3?3:x or ((x+1)*3)/4 instead. | |
REDUCE=[0,1,2,3,3] | |
# Calculate JDN, using a block to do the final part of the calculation. | |
def to_jdn(year,month,day) | |
a=(14-month)/12 | |
y=year+4800-a | |
m=month+12*a-3 | |
day+MDAY[m]+365*y+y/4+yield(y) | |
end | |
# Calculate date, given centuries from -4800,3,1 and remainder days in century. | |
def to_date(c,dc) | |
# whole quadrennials | |
q=dc/1461 | |
# remainder days in quadrennial | |
dq=dc%1461 | |
# whole years | |
a=REDUCE[dq/365] | |
# remainder days in year | |
d=dq-a*365 | |
# whole months (magic!) | |
m=(((d*5)+308)/153)-2 | |
# remainder days in month | |
dm=d-MDAY[m] | |
# total years | |
y=c*100+q*4+a | |
# convert to conventional form of date | |
year=y-4800+(m+2)/12 | |
month=((m+2)%12)+1 | |
day=dm+1 | |
{:year=>year, :month=>month, :day=>day} | |
end | |
public | |
# Calculate the Gregorian date on which a give Julian Day Number begins. | |
# This is an aternative, slightly faster algorithm, taken from | |
# http://www.astro.uu.nl/~strous/AA/en/reken/juliaansedag.html | |
def jdn_to_gregorian_direct(jdn) | |
s1=jdn+68569 | |
n=(4*s1)/146097 | |
s2=s1-(146097*n+3)/4 | |
i=(4000*(s2+1))/1461001 | |
s3=s2-(1461*i)/4+31 | |
q=(80*s3)/2447 | |
day=s3-(2447*q)/80 | |
s4=q/11 | |
month=q+2-12*s4 | |
year=100*(n-49)+i+s4 | |
{:year=>year, :month=>month, :day=>day} | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment