Skip to content

Instantly share code, notes, and snippets.

@janfri
Last active April 25, 2016 09:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save janfri/df088e6adf1afbdbf35b to your computer and use it in GitHub Desktop.
Save janfri/df088e6adf1afbdbf35b to your computer and use it in GitHub Desktop.
Sunrise and sunset
#!/usr/bin/env ruby
# -- encoding: utf-8 --
module Astronomy
# Floor as function
def floor x
x.floor
end
# Defining of trigonomtetrical functions in degrees
def self.def_trig *func
func.collect! { |f| f.to_s }
func.each do |f|
module_eval <<-EVAL
def #{f} x
Math.#{f}(x*Math::PI/180)
end
def a#{f} x
Math.a#{f}(x)*180/Math::PI
end
EVAL
end
end
def_trig :sin, :cos, :tan
OFFICIAL_ZENITH = 90.0 + 50.0/60.0 # 90°50'
CIVIL_ZENITH = 96
NAUTICAL_ZENITH = 102
ASTRONOMICAL_ZENITH = 108
# Algorithm see:
# http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
# date: date of sunrise/sunset
# latitude, longitude: location for sunrise/sunset
# zenith: Sun's zenith for sunrise/sunset
# offical = 90 degrees 50'
# civil = 96 degrees
# nautical = 102 degrees
# astronomical = 108 degrees
#
# NOTE: longitude is positive for East and negative for West
def sun_rise_set(date, latitude, longitude, zenith, rise_set)
# 1. first sun_rise_set the day of the year
n = date.yday
# 2. convert the longitude to hour value and sun_rise_set an approximate time
lnghour = longitude / 15
if rise_set == :rise
# if rising time is desired:
t = n + ((6 - lnghour) / 24)
else
# if setting time is desir.ed:
t = n + ((18 - lnghour) / 24)
end
# 3. sun_rise_set the sun's mean anomaly
m = (0.9856 * t) - 3.289
# 4. sun_rise_set the sun's true longitude
l = m + (1.916 * sin(m)) + (0.020 * sin(2 * m)) + 282.634
# note: l potentially needs to be adjusted into the range [0,360) by
# adding/subtracting 360
l = l % 360
# 5a. sun_rise_set the sun's right ascension
ra = atan(0.91764 * tan(l))
# note: ra potentially needs to be adjusted into the range [0,360) by
# adding/subtracting 360
ra = ra % 360
# 5b. right ascension value needs to be in the same quadrant as l
lquadrant = (floor( l/90)) * 90
raquadrant = (floor(ra/90)) * 90
ra = ra + (lquadrant - raquadrant)
# 5c. right ascension value needs to be converted into hours
ra = ra / 15.0
# 6. sun_rise_set the sun's declination
sindec = 0.39782 * sin(l)
cosdec = cos(asin(sindec))
# 7a. sun_rise_set the sun's local hour angle
cosh = (cos(zenith) - (sindec * sin(latitude))) / (cosdec * cos(latitude))
if (cosh > 1)
# the sun never rises on this location (on the specified date)
return nil
end
if (cosh < -1)
# the sun never sets on this location (on the specified date)
return nil
end
# 7b. finish calculating h and convert into hours
if rise_set == :rise
# if if rising time is desired:
h = 360 - acos(cosh)
else
#if setting time is desired:
h = acos(cosh)
end
h = h / 15
# 8. sun_rise_set local mean time of rising/setting
t = h + ra - (0.06571 * t) - 6.622
# 9. adjust back to utc
ut = t - lnghour
# note: ut potentially needs to be adjusted into the range [0,24) by
# adding/subtracting 24
ut = ut % 24
Time.utc(date.year, date.month, date.day, ut.truncate,
((ut- ut.truncate).abs * 60).truncate)
# 10. convert ut value to local time zone of latitude/longitude
# localt = ut + localoffset
end
end
#------------------------------------------------------------------------------
if __FILE__ == $0
if ARGV.length != 2
puts "Aufruf: ruby sun.rb [geogr. Breite] [geogr. Länge]"
puts " z.B.: ruby sun.rb 53.09 8.13"
exit -1
end
lat, long = ARGV[0..1].collect{ |arg| arg.to_f }
include Astronomy
# Redefining of to_s
class Time
def to_s
l = self.localtime
"%02d:%02d (%s)" % [l.hour, l.min, l.zone]
end
end
today = Time.new
puts "=" * 36
time = sun_rise_set(today, lat, long, ASTRONOMICAL_ZENITH, :rise)
puts "Astronomische Dämmerung: #{time}"
time = sun_rise_set(today, lat, long, NAUTICAL_ZENITH, :rise)
puts "Nautische Dämmerung: #{time}"
time = sun_rise_set(today, lat, long, CIVIL_ZENITH, :rise)
puts "Bürgerliche Dämmerung: #{time}"
time = sun_rise_set(today, lat, long, OFFICIAL_ZENITH, :rise)
puts "Sonnenaufgang: #{time}"
puts "-" * 36
time = sun_rise_set(today, lat, long, OFFICIAL_ZENITH, :set)
puts "Sonnenuntergang: #{time}"
time = sun_rise_set(today, lat, long, CIVIL_ZENITH, :set)
puts "Bürgerliche Dämmerung: #{time}"
time = sun_rise_set(today, lat, long, NAUTICAL_ZENITH, :set)
puts "Nautische Dämmerung: #{time}"
time = sun_rise_set(today, lat, long, ASTRONOMICAL_ZENITH, :set)
puts "Astronomische Dämmerung: #{time}"
puts "=" * 36
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment