Last active
April 25, 2016 09:26
-
-
Save janfri/df088e6adf1afbdbf35b to your computer and use it in GitHub Desktop.
Sunrise and sunset
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
#!/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