sun-times 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +20 -0
- data/README +35 -0
- data/Rakefile +48 -0
- data/lib/sun_times.rb +179 -0
- data/test/calculate_test.rb +60 -0
- data/test/test_all.rb +3 -0
- metadata +62 -0
data/COPYING
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Joe Yates
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
== SunTimes
|
2
|
+
|
3
|
+
Calculates sunrise and sunset times.
|
4
|
+
|
5
|
+
An implementation of the algorithm descibed at http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
|
6
|
+
|
7
|
+
== References
|
8
|
+
|
9
|
+
* http://www.astro.uu.nl/~strous/AA/en/reken/zonpositie.html - Calculations
|
10
|
+
* http://williams.best.vwh.net/sunrise_sunset_algorithm.htm - Algorithm
|
11
|
+
* http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/264573 - Ken Bloom's implementation
|
12
|
+
|
13
|
+
== Licence
|
14
|
+
|
15
|
+
This code is free to use under the terms of the MIT licence:
|
16
|
+
|
17
|
+
Copyright (c) 2010 Joe Yates
|
18
|
+
|
19
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
20
|
+
of this software and associated documentation files (the "Software"), to
|
21
|
+
deal in the Software without restriction, including without limitation the
|
22
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
23
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
24
|
+
furnished to do so, subject to the following conditions:
|
25
|
+
|
26
|
+
The above copyright notice and this permission notice shall be included in
|
27
|
+
all copies or substantial portions of the Software.
|
28
|
+
|
29
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
30
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
31
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
32
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
33
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
34
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
35
|
+
IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/clean'
|
6
|
+
|
7
|
+
$:.unshift(File.dirname(__FILE__) + '/lib')
|
8
|
+
require 'sun_times'
|
9
|
+
|
10
|
+
RDOC_OPTS = ['--quiet', '--title', 'Sun Times Calculator', '--main', 'README', '--inline-source']
|
11
|
+
CLEAN.include 'doc'
|
12
|
+
|
13
|
+
task :default => :test
|
14
|
+
|
15
|
+
spec = Gem::Specification.new do |s|
|
16
|
+
s.name = 'sun-times'
|
17
|
+
s.summary = 'Module which calculates sunrise and sunset times'
|
18
|
+
s.version = SunTimes::VERSION::STRING
|
19
|
+
|
20
|
+
s.homepage = 'http://github.com/timoschilling/sun-times'
|
21
|
+
s.author = ['Joe Yates', 'Timo Schilling']
|
22
|
+
s.email = ['joe.g.yates@gmail.com', 'timo@schilling.io']
|
23
|
+
|
24
|
+
s.files = ['README', 'COPYING', 'Rakefile'] + FileList['{lib,test}/**/*.rb']
|
25
|
+
s.require_paths = ['lib']
|
26
|
+
|
27
|
+
s.has_rdoc = true
|
28
|
+
s.rdoc_options += RDOC_OPTS
|
29
|
+
s.extra_rdoc_files = ['README', 'COPYING']
|
30
|
+
|
31
|
+
s.test_file = 'test/test_all.rb'
|
32
|
+
end
|
33
|
+
|
34
|
+
Rake::TestTask.new do |t|
|
35
|
+
t.libs << 'test'
|
36
|
+
t.test_files = FileList['test/*_test.rb']
|
37
|
+
t.verbose = true
|
38
|
+
end
|
39
|
+
|
40
|
+
Rake::RDocTask.new do |rdoc|
|
41
|
+
rdoc.rdoc_dir = 'doc/rdoc'
|
42
|
+
rdoc.options += RDOC_OPTS
|
43
|
+
rdoc.main = "README"
|
44
|
+
rdoc.rdoc_files.add ['README', 'COPYING', 'lib/**/*.rb']
|
45
|
+
end
|
46
|
+
|
47
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
48
|
+
end
|
data/lib/sun_times.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010 Joe Yates
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
# Algorithm from http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
|
25
|
+
|
26
|
+
require 'date'
|
27
|
+
|
28
|
+
module SunTimes
|
29
|
+
|
30
|
+
module VERSION #:nodoc:
|
31
|
+
MAJOR = 0
|
32
|
+
MINOR = 1
|
33
|
+
TINY = 2
|
34
|
+
|
35
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
36
|
+
end
|
37
|
+
|
38
|
+
DEFAULT_ZENITH = 90.83333
|
39
|
+
KNOWN_EVENTS = [:rise, :set]
|
40
|
+
DEGREES_PER_HOUR = 360.0 / 24.0
|
41
|
+
|
42
|
+
# Helper method: calculates sunrise, with the same parameters as calculate
|
43
|
+
def SunTimes.rise(date, latitude, longitude, options = {})
|
44
|
+
calculate(:rise, date, latitude, longitude, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Helper method: calculates sunset, with the same parameters as calculate
|
48
|
+
def SunTimes.set(date, latitude, longitude, options = {})
|
49
|
+
calculate(:set, date, latitude, longitude, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Calculates the sunrise or sunset time for a specific date and location
|
53
|
+
#
|
54
|
+
# ==== Parameters
|
55
|
+
# * +event+ - One of :rise, :set.
|
56
|
+
# * +date+ - An object that responds to yday.
|
57
|
+
# * +latitude+ - The latitude of the location in degrees.
|
58
|
+
# * +longitude+ - The longitude of the location in degrees.
|
59
|
+
# * +options+ - Additional option is <tt>:zenith</tt>.
|
60
|
+
#
|
61
|
+
# ==== Example
|
62
|
+
# SunTimes.calculate(:rise, Date.new(2010, 3, 8), 43.779, 11.432)
|
63
|
+
# > Mon Mar 08 05:39:53 UTC 2010
|
64
|
+
def SunTimes.calculate(event, date, latitude, longitude, options = {})
|
65
|
+
raise "Unknown event '#{ event }'" if KNOWN_EVENTS.find_index(event).nil?
|
66
|
+
zenith = options.delete(:zenith) || DEFAULT_ZENITH
|
67
|
+
|
68
|
+
# lngHour
|
69
|
+
longitude_hour = longitude / DEGREES_PER_HOUR
|
70
|
+
|
71
|
+
# t
|
72
|
+
base_time = event == :rise ? 6.0 : 18.0
|
73
|
+
approximate_time = date.yday + (base_time - longitude_hour) / 24.0
|
74
|
+
|
75
|
+
# M
|
76
|
+
mean_sun_anomaly = (0.9856 * approximate_time) - 3.289
|
77
|
+
|
78
|
+
# L
|
79
|
+
sun_true_longitude = mean_sun_anomaly +
|
80
|
+
(1.916 * Math.sin(degrees_to_radians(mean_sun_anomaly))) +
|
81
|
+
(0.020 * Math.sin(2 * degrees_to_radians(mean_sun_anomaly))) +
|
82
|
+
282.634
|
83
|
+
sun_true_longitude = coerce_degrees(sun_true_longitude)
|
84
|
+
|
85
|
+
# RA
|
86
|
+
tan_right_ascension = 0.91764 * Math.tan(degrees_to_radians(sun_true_longitude))
|
87
|
+
sun_right_ascension = radians_to_degrees(Math.atan(tan_right_ascension))
|
88
|
+
sun_right_ascension = coerce_degrees(sun_right_ascension)
|
89
|
+
|
90
|
+
# right ascension value needs to be in the same quadrant as L
|
91
|
+
sun_true_longitude_quadrant = (sun_true_longitude / 90.0).floor * 90.0
|
92
|
+
sun_right_ascension_quadrant = (sun_right_ascension / 90.0).floor * 90.0
|
93
|
+
sun_right_ascension += (sun_true_longitude_quadrant - sun_right_ascension_quadrant)
|
94
|
+
|
95
|
+
# RA = RA / 15
|
96
|
+
sun_right_ascension_hours = sun_right_ascension / DEGREES_PER_HOUR
|
97
|
+
|
98
|
+
sin_declination = 0.39782 * Math.sin(degrees_to_radians(sun_true_longitude))
|
99
|
+
cos_declination = Math.cos(Math.asin(sin_declination))
|
100
|
+
|
101
|
+
cos_local_hour_angle =
|
102
|
+
(Math.cos(degrees_to_radians(zenith)) - (sin_declination * Math.sin(degrees_to_radians(latitude)))) /
|
103
|
+
(cos_declination * Math.cos(degrees_to_radians(latitude)))
|
104
|
+
|
105
|
+
# the sun never rises on this location (on the specified date)
|
106
|
+
return nil if cos_local_hour_angle > 1
|
107
|
+
# the sun never sets on this location (on the specified date)
|
108
|
+
return nil if cos_local_hour_angle < -1
|
109
|
+
|
110
|
+
# H
|
111
|
+
suns_local_hour =
|
112
|
+
if event == :rise
|
113
|
+
360 - radians_to_degrees(Math.acos(cos_local_hour_angle))
|
114
|
+
else
|
115
|
+
radians_to_degrees(Math.acos(cos_local_hour_angle))
|
116
|
+
end
|
117
|
+
|
118
|
+
# H = H / 15
|
119
|
+
suns_local_hour_hours = suns_local_hour / DEGREES_PER_HOUR
|
120
|
+
|
121
|
+
# T = H + RA - (0.06571 * t) - 6.622
|
122
|
+
local_mean_time = suns_local_hour_hours + sun_right_ascension_hours - (0.06571 * approximate_time) - 6.622
|
123
|
+
|
124
|
+
# UT = T - lngHour
|
125
|
+
gmt_hours = local_mean_time - longitude_hour
|
126
|
+
gmt_hours -= 24.0 if gmt_hours > 24
|
127
|
+
gmt_hours += 24.0 if gmt_hours < 0
|
128
|
+
|
129
|
+
case
|
130
|
+
when date.respond_to?( :offset )
|
131
|
+
offset_hours = date.offset * 24
|
132
|
+
when date.respond_to?( :gmt_offset )
|
133
|
+
offset_hours = date.gmt_offset / 3600
|
134
|
+
else
|
135
|
+
offset_hours = nil
|
136
|
+
end
|
137
|
+
|
138
|
+
if ! offset_hours.nil?
|
139
|
+
if gmt_hours + offset_hours < 0
|
140
|
+
next_day = Date.new(date.year, date.month, date.day + 1)
|
141
|
+
return calculate(event, next_day, latitude, longitude, options = {})
|
142
|
+
end
|
143
|
+
if gmt_hours + offset_hours > 24
|
144
|
+
previous_day = Date.new(date.year, date.month, date.day + 1)
|
145
|
+
return calculate(event, previous_day, latitude, longitude, options = {})
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
hour = gmt_hours.floor
|
150
|
+
hour_remainder = (gmt_hours.to_f - hour.to_f) * 60.0
|
151
|
+
minute = hour_remainder.floor
|
152
|
+
seconds = (hour_remainder - minute) * 60.0
|
153
|
+
|
154
|
+
Time.gm(date.year, date.month, date.day, hour, minute, seconds)
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
def SunTimes.degrees_to_radians(d)
|
160
|
+
d.to_f / 360.0 * 2.0 * Math::PI
|
161
|
+
end
|
162
|
+
|
163
|
+
def SunTimes.radians_to_degrees(r)
|
164
|
+
r.to_f * 360.0 / (2.0 * Math::PI)
|
165
|
+
end
|
166
|
+
|
167
|
+
def SunTimes.coerce_degrees(d)
|
168
|
+
if d < 0
|
169
|
+
d += 360
|
170
|
+
return coerce_degrees(d)
|
171
|
+
end
|
172
|
+
if d >= 360
|
173
|
+
d -= 360
|
174
|
+
return coerce_degrees(d)
|
175
|
+
end
|
176
|
+
d
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
3
|
+
require 'test/unit'
|
4
|
+
require 'sun_times'
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
class SunTimesTest < Test::Unit::TestCase
|
8
|
+
|
9
|
+
def test_rise_20100308_pontassieve
|
10
|
+
rise = SunTimes.calculate(:rise, Date.new(2010, 3, 8), 43.779, 11.432)
|
11
|
+
assert_equal(Time.gm(2010, 3, 8, 5, 39, 53), rise)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_set_20100308_pontassieve
|
15
|
+
set = SunTimes.calculate(:set, Date.new(2010, 3, 8), 43.779, 11.432)
|
16
|
+
assert_equal(Time.gm(2010, 3, 8, 17, 11, 16), set)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_rise_helper
|
20
|
+
rise = SunTimes.rise(Date.new(2010, 3, 8), 43.779, 11.432)
|
21
|
+
assert_equal(Time.gm(2010, 3, 8, 5, 39, 53), rise)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_set_helper
|
25
|
+
set = SunTimes.set(Date.new(2010, 3, 8), 43.779, 11.432)
|
26
|
+
assert_equal(Time.gm(2010, 3, 8, 17, 11, 16), set)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_midnight_sun_on_20100621_north_cape
|
30
|
+
rise = SunTimes.calculate(:rise, Date.new(2010, 6, 21), 71.170219, 25.785556)
|
31
|
+
assert_nil(rise)
|
32
|
+
set = SunTimes.calculate(:set, Date.new(2010, 6, 21), 71.170219, 25.785556)
|
33
|
+
assert_nil(set)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_unknown_event
|
37
|
+
assert_raise(RuntimeError) { SunTimes.calculate(:foo, Date.new(2010, 3, 8), 43.779, 11.432) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_time
|
41
|
+
datetime = Time.gm(2010, 6, 13, 0, 0, 0)
|
42
|
+
set = SunTimes.calculate(:set, datetime, 43.779, 11.432)
|
43
|
+
assert_equal(Time.gm(2010, 6, 13, 18, 56, 55), set)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_datetime
|
47
|
+
datetime = DateTime.new(2010, 6, 13, 0, 0, 0)
|
48
|
+
set = SunTimes.calculate(:set, datetime, 43.779, 11.432)
|
49
|
+
assert_equal(Time.gm(2010, 6, 13, 18, 56, 55), set)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_respects_timezone_if_supplied
|
53
|
+
pst = DateTime.new(2011, 12, 13, 0, 0, 0, Rational(-8, 24))
|
54
|
+
set = SunTimes.calculate(:set, pst, 45.52, -122.681944)
|
55
|
+
result_datetime = DateTime.new(set.year, set.month, set.day, set.hour, set.min, set.sec, 0)
|
56
|
+
assert(pst < result_datetime)
|
57
|
+
assert(pst + 1 > result_datetime)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/test/test_all.rb
ADDED
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sun-times
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joe Yates
|
9
|
+
- Timo Schilling
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-05-20 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
15
|
+
description:
|
16
|
+
email:
|
17
|
+
- joe.g.yates@gmail.com
|
18
|
+
- timo@schilling.io
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files:
|
22
|
+
- README
|
23
|
+
- COPYING
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- COPYING
|
27
|
+
- Rakefile
|
28
|
+
- lib/sun_times.rb
|
29
|
+
- test/calculate_test.rb
|
30
|
+
- test/test_all.rb
|
31
|
+
homepage: http://github.com/timoschilling/sun-times
|
32
|
+
licenses: []
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options:
|
35
|
+
- --quiet
|
36
|
+
- --title
|
37
|
+
- Sun Times Calculator
|
38
|
+
- --main
|
39
|
+
- README
|
40
|
+
- --inline-source
|
41
|
+
require_paths:
|
42
|
+
- lib
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
45
|
+
requirements:
|
46
|
+
- - ! '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 1.8.24
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: Module which calculates sunrise and sunset times
|
61
|
+
test_files:
|
62
|
+
- test/test_all.rb
|