Skip to content

Instantly share code, notes, and snippets.

@pilotmoon
Created April 8, 2011 18:21
Show Gist options
  • Save pilotmoon/910427 to your computer and use it in GitHub Desktop.
Save pilotmoon/910427 to your computer and use it in GitHub Desktop.
# 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