Skip to content

Instantly share code, notes, and snippets.

@mhorbul
Created December 18, 2009 01:04
Show Gist options
  • Save mhorbul/259180 to your computer and use it in GitHub Desktop.
Save mhorbul/259180 to your computer and use it in GitHub Desktop.
require 'time'
def deg2rad(d)
(d/180.0)*Math::PI
end
def rad2deg(r)
(r/Math::PI)*180
end
def jd(year, month, day)
if (month <= 2)
year -= 1; month += 12
end
a = (year/100).floor
b = 2 - a + (a/4).floor
(365.25*(year + 4716)).floor +
(30.6001*(month+1)).floor +
day + b - 1524.5
end
def jd2cent(jd)
(jd - 2451545.0)/36525.0
end
def cent2jd(t)
t * 36525.0 + 2451545.0
end
def mean_obliquity_of_ecliptic(t)
seconds = 21.448 - t*(46.8150 + t*(0.00059 - t*(0.001813)))
23.0 + (26.0 + (seconds/60.0))/60.0
end
def obliquity_correction(t)
e0 = mean_obliquity_of_ecliptic(t)
omega = 125.04 - 1934.136 * t
e0 + 0.00256 * Math.cos(deg2rad(omega))
end
def sun_true_long(t)
geom_mean_long_sun(t) + sun_eq_of_center(t)
end
def sun_apparent_long(t)
o = sun_true_long(t)
omega = 125.04 - 1934.136 * t;
o - 0.00569 - 0.00478 * Math.sin(deg2rad(omega))
end
def sun_declination(t)
e = obliquity_correction(t)
lambda = sun_apparent_long(t)
sint = Math.sin(deg2rad(e)) * Math.sin(deg2rad(lambda))
rad2deg(Math.asin(sint))
end
def sun_eq_of_center(t)
m = geom_mean_anomaly_sun(t)
mrad = deg2rad(m)
sinm = Math.sin(mrad);
sin2m = Math.sin(mrad+mrad);
sin3m = Math.sin(mrad+mrad+mrad);
sinm * (1.914602 - t * (0.004817 + 0.000014 * t)) +
sin2m * (0.019993 - 0.000101 * t) + sin3m * 0.000289
end
def geom_mean_long_sun(t)
l0 = 280.46646 + t * (36000.76983 + 0.0003032 * t)
l0 += (l0 < 0) ? 360 : (l0 > 360 ? -360 : 0)
end
def eccentricity_earth_orbit(t)
0.016708634 - t * (0.000042037 + 0.0000001267 * t)
end
def geom_mean_anomaly_sun(t)
357.52911 + t * (35999.05029 - 0.0001537 * t)
end
def equation_of_time(t)
epsilon = obliquity_correction(t)
l0 = geom_mean_long_sun(t)
e = eccentricity_earth_orbit(t)
m = geom_mean_anomaly_sun(t)
y = Math.tan(deg2rad(epsilon)/2.0)
y *= y
sin2l0 = Math.sin(2.0 * deg2rad(l0))
sinm = Math.sin(deg2rad(m))
cos2l0 = Math.cos(2.0 * deg2rad(l0))
sin4l0 = Math.sin(4.0 * deg2rad(l0))
sin2m = Math.sin(2.0 * deg2rad(m))
etime = y * sin2l0 - 2.0 * e * sinm + 4.0 * e * y *
sinm * cos2l0 - 0.5 * y * y *
sin4l0 - 1.25 * e * e * sin2m
rad2deg(etime)*4.0
end
def sol_noon_utc(t, longitude)
tnoon = jd2cent(cent2jd(t) + longitude/360.0)
eq_time = equation_of_time(tnoon)
sol_noon_utc = 720 + (longitude * 4) - eq_time
newt = jd2cent(cent2jd(t) -0.5 + sol_noon_utc/1440.0)
720 + (longitude * 4) - equation_of_time(newt)
end
def hour_angle(lat, solar_dec)
lat_rad = deg2rad(lat)
sd_rad = deg2rad(solar_dec)
Math.acos(Math.cos(deg2rad(90.833))/
(Math.cos(lat_rad)*Math.cos(sd_rad))-
Math.tan(lat_rad) * Math.tan(sd_rad))
end
def min2time(minutes, date)
float_hours = minutes / 60.0
if float_hours >= 24
date += 24 * 3600
float_hours = float_hours - 24
end
hours = float_hours.floor
float_min = 60.0 * (float_hours - hours)
min = float_min.floor
float_sec = 60.0 * (float_min - min)
sec = float_sec.floor
Time.gm(date.year, date.month, date.day, hours, min, sec)
end
def calc_sun_rise_or_set(t, latitude, longitude, type)
eq_time = equation_of_time(t)
solar_dec = sun_declination(t)
hour_angle = hour_angle(latitude, solar_dec)
hour_angle *= -1 if type == :sunset
time_diff = 4 * (longitude - rad2deg(hour_angle))
720 + time_diff - eq_time
end
def sun_rise_or_set_utc(date, latitude, longitude, utc_offset, type)
jd = jd(date.year, date.month, date.day)
t = jd2cent(jd)
noonmin = sol_noon_utc(t, longitude)
tnoon = jd2cent(jd + noonmin/1440.0)
time_utc = calc_sun_rise_or_set(tnoon, latitude, longitude, type)
newt = jd2cent(cent2jd(t) + time_utc/1440.0)
time_gmt = calc_sun_rise_or_set(newt, latitude, longitude, type)
min2time(time_gmt, date) + utc_offset * 3600
end
date = Time.parse('12/17/2009')
lat = 37.766666666666666
lng = 122.41666666666667
utc_offset = -8
puts sun_rise_or_set_utc(date, lat, lng, utc_offset, :sunrise)
puts sun_rise_or_set_utc(date, lat, lng, utc_offset, :sunset)
@DouglasAllen
Copy link

You don't really need to calculate a Julian Day Number. Ruby has that in the Date and DateTime classes of the standard library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment