sun 0.1.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -9
- data/README.md +44 -10
- data/Rakefile +1 -1
- data/circle.yml +3 -0
- data/lib/sun.rb +84 -33
- data/lib/sun/version.rb +1 -1
- data/sun.gemspec +2 -10
- metadata +23 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 981419de39da6b66ce62873498c91aee04386fa0
|
4
|
+
data.tar.gz: 0232e38b4729004f092cfb1cb40e724c4167d3cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01e62ce25b8f19b34c9be095521bb76c91cc534a5323154705b4ea0e3792f9bb6d9367369512f4cf292c0f37cf34de38ec7283fd6e671a0db27990b1c7be818f
|
7
|
+
data.tar.gz: 5845f933f5011c81a0089cb9f38eeff5862497c1d70b42fbd2cb58474a4fc2c771b19af6d7842d87b724576fa74a0166d72d67db8380e0ca0b010cd77e5b0094
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,16 @@
|
|
1
|
-
#
|
1
|
+
# Sun
|
2
2
|
|
3
|
-
|
3
|
+
**Sunrise / sunset times for Ruby**
|
4
4
|
|
5
|
-
|
5
|
+
* [Source Code]
|
6
|
+
* [API documentation]
|
7
|
+
* [Rubygem]
|
8
|
+
|
9
|
+
[Source Code]: https://github.com/allspiritseve/sun "Source code at Github"
|
10
|
+
[API documentation]: http://rubydoc.info/gems/sun/frames "RDoc API Documentation at RubyDoc.info"
|
11
|
+
[Rubygem]: http://rubygems.org/gems/sun "Ruby gem at RubyGems.org"
|
12
|
+
|
13
|
+
Sun is a solar calculator for Ruby based on the [National Oceanic & Atmospheric Administration (NOAA) solar calculator](http://www.esrl.noaa.gov/gmd/grad/solcalc/). Sunrise and sunset results are apparent times and not actual times (due to atmospheric refraction, apparent sunrise occurs shortly before the sun crosses above the horizon and apparent sunset occurs shortly after the sun crosses below the horizon).
|
6
14
|
|
7
15
|
## Installation
|
8
16
|
|
@@ -22,20 +30,46 @@ Or install it yourself as:
|
|
22
30
|
|
23
31
|
## Usage
|
24
32
|
|
25
|
-
|
33
|
+
```ruby
|
34
|
+
time = Time.new(2015, 1, 1, 12, 0, 0, '-05:00')
|
35
|
+
latitude = 40.75
|
36
|
+
longitude = -73.99
|
26
37
|
|
27
|
-
|
38
|
+
# Sunrise
|
39
|
+
Sun.sunrise(time, latitude, longitude) # => 2015-01-01 07:20:02 -0500
|
28
40
|
|
29
|
-
|
41
|
+
# Solar noon
|
42
|
+
Sun.solar_noon(time, latitude, longitude) # => 2015-01-01 11:59:09 -0500
|
30
43
|
|
31
|
-
|
44
|
+
# Sunset
|
45
|
+
Sun.sunset(time, latitude, longitude) # => 2015-01-01 16:38:16 -0500
|
32
46
|
|
33
|
-
|
47
|
+
# Sunrise in minutes after midnight (UTC)
|
48
|
+
Sun.sunrise_minutes(time, latitude, longitude) # => 740.0366212342198
|
49
|
+
|
50
|
+
# Solar noon in minutes after midnight (UTC)
|
51
|
+
Sun.solar_noon(time, latitude, longitude) # => 1019.1596410575343
|
52
|
+
|
53
|
+
# Sunset in minutes after midnight (UTC)
|
54
|
+
Sun.sunset(time, latitude, longitude) # => 1298.2826608808487
|
55
|
+
```
|
34
56
|
|
35
|
-
|
57
|
+
## Notes
|
36
58
|
|
59
|
+
All of the above methods accept Date or Time objects for `time`. If a `Time` object is passed, the calculations will be performed on the return value of [`Time#to_date`](http://ruby-doc.org/stdlib-2.2.2/libdoc/date/rdoc/Time.html#method-i-to_date), which is timezone-dependent (for example, 1am in Michigan is 10pm on the previous day in California). To force calculations on a specific date regardless of timezone, pass a `Date` object.
|
60
|
+
|
61
|
+
Sun times are returned as [`Time`](http://ruby-doc.org/core-2.2.2/Time.html) objects in the local system timezone. To convert to a different timezone, you can use [`TZInfo::Timezone#utc_to_local`](http://www.rubydoc.info/gems/tzinfo/TZInfo/Timezone#utc_to_local-instance_method) or [`ActiveSupport::TimeZone#at`](http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html#method-i-at).
|
62
|
+
|
63
|
+
## References
|
64
|
+
|
65
|
+
* [NOAA Solar Calculation Details](http://www.esrl.noaa.gov/gmd/grad/solcalc/calcdetails.html)
|
66
|
+
* [NOAA Solar Calculator](http://www.esrl.noaa.gov/gmd/grad/solcalc/)
|
67
|
+
* [Wikipedia: Sunrise equation](https://en.wikipedia.org/wiki/Sunrise_equation)
|
68
|
+
|
69
|
+
## Contributing
|
70
|
+
|
71
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/allspiritseve/sun. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
37
72
|
|
38
73
|
## License
|
39
74
|
|
40
75
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
41
|
-
|
data/Rakefile
CHANGED
data/circle.yml
ADDED
data/lib/sun.rb
CHANGED
@@ -1,34 +1,67 @@
|
|
1
|
+
require 'date'
|
1
2
|
require 'sun/version'
|
2
3
|
|
3
4
|
module Sun
|
5
|
+
# The approximate correction for atmospheric refraction at sunrise and sunset
|
4
6
|
SOLAR_ZENITH = 90.833
|
5
7
|
|
6
|
-
#
|
8
|
+
# 2000-01-01 12:00:00 UTC in Julian days
|
7
9
|
JULIAN_CONSTANT = 2451545.to_r
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
class Error < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class InvalidTime < Error
|
15
|
+
end
|
16
|
+
|
17
|
+
class InvalidCoordinates < Error
|
13
18
|
end
|
14
19
|
|
20
|
+
# Sun times (UTC)
|
21
|
+
|
15
22
|
def self.sunrise(time, latitude, longitude)
|
16
|
-
|
17
|
-
|
23
|
+
sun_time(:sunrise, time, latitude, longitude)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.solar_noon(time, latitude, longitude)
|
27
|
+
sun_time(:solar_noon, time, latitude, longitude)
|
18
28
|
end
|
19
29
|
|
20
30
|
def self.sunset(time, latitude, longitude)
|
21
|
-
|
22
|
-
|
31
|
+
sun_time(:sunset, time, latitude, longitude)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sun times in minutes after midnight (UTC)
|
35
|
+
|
36
|
+
def self.sunrise_minutes(time, latitude, longitude)
|
37
|
+
sun_time_minutes(:sunrise, time, latitude, longitude)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.solar_noon_minutes(time, latitude, longitude)
|
41
|
+
sun_time_minutes(:solar_noon, time, latitude, longitude)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.sunset_minutes(time, latitude, longitude)
|
45
|
+
sun_time_minutes(:sunset, time, latitude, longitude)
|
23
46
|
end
|
24
47
|
|
25
48
|
# Helpers
|
49
|
+
|
50
|
+
def self.date(time)
|
51
|
+
case time
|
52
|
+
when Date then time
|
53
|
+
when Time then time.to_date
|
54
|
+
else
|
55
|
+
raise InvalidTime, "must pass a Date or Time object"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
26
59
|
def self.degrees(radians)
|
27
|
-
180
|
60
|
+
Rational(180 * radians, Math::PI)
|
28
61
|
end
|
29
62
|
|
30
63
|
def self.radians(degrees)
|
31
|
-
Math::PI * degrees
|
64
|
+
Rational(Math::PI * degrees, 180)
|
32
65
|
end
|
33
66
|
|
34
67
|
def self.date_to_unix_time(date)
|
@@ -36,11 +69,42 @@ module Sun
|
|
36
69
|
end
|
37
70
|
|
38
71
|
def self.date_at_time(date, minutes)
|
39
|
-
date_to_unix_time(date) + minutes * 60
|
72
|
+
Time.at(date_to_unix_time(date) + minutes * 60)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Base our calculations off the astronomical julian date for our input time.
|
76
|
+
# Our formula is sensitive to time of day, so we ignore it in order to give
|
77
|
+
# consistent results for any time on the same date.
|
78
|
+
def self.sun_time(type, time, latitude, longitude)
|
79
|
+
date = date(time)
|
80
|
+
minutes = sun_time_minutes(type, date, latitude, longitude)
|
81
|
+
date_at_time(date, minutes)
|
40
82
|
end
|
41
83
|
|
84
|
+
def self.sun_time_minutes(type, time, latitude, longitude)
|
85
|
+
date = date(time)
|
86
|
+
offset = offset_multiplier(type) * 4 * hour_angle(date, latitude)
|
87
|
+
720 - (4 * longitude) - equation_of_time(date, longitude) + offset
|
88
|
+
rescue Math::DomainError
|
89
|
+
raise InvalidCoordinates, "Could not determine sun times for coordinates: #{latitude}, #{longitude}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.offset_multiplier(type)
|
93
|
+
case type
|
94
|
+
when :sunrise then -1
|
95
|
+
when :solar_noon then 0
|
96
|
+
when :sunset then 1
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Calculations
|
101
|
+
|
42
102
|
def self.julian_days(time)
|
43
|
-
time.
|
103
|
+
if time.is_a?(Time)
|
104
|
+
time.to_datetime.ajd
|
105
|
+
else
|
106
|
+
date(time).ajd
|
107
|
+
end
|
44
108
|
end
|
45
109
|
|
46
110
|
def self.julian_century(time)
|
@@ -59,9 +123,8 @@ module Sun
|
|
59
123
|
357.52911 + julian_century * (35999.05029 - 0.0001537 * julian_century)
|
60
124
|
end
|
61
125
|
|
62
|
-
# MOD(280.46646+G2*(36000.76983 + G2*0.0003032),360)
|
63
126
|
def self.geometric_mean_longitude(julian_century)
|
64
|
-
280.46646 + julian_century * (36000.76983 + julian_century * 0.0003032) % 360
|
127
|
+
(280.46646 + julian_century * (36000.76983 + julian_century * 0.0003032)) % 360
|
65
128
|
end
|
66
129
|
|
67
130
|
def self.y(oblique_correction)
|
@@ -75,7 +138,6 @@ module Sun
|
|
75
138
|
def self.equation_of_center(julian_century)
|
76
139
|
geometric_mean_anomoly = geometric_mean_anomoly(julian_century)
|
77
140
|
Math.sin(radians(geometric_mean_anomoly)) * (1.914602 - julian_century * (0.004817 + 0.000014 * julian_century)) + Math.sin(radians(2 * geometric_mean_anomoly)) * (0.019993 - 0.000101 * julian_century) + Math.sin(radians(3 * geometric_mean_anomoly)) * 0.00028
|
78
|
-
# =SIN(RADIANS(J2))*(1.914602-G2*(0.004817+0.000014*G2))+SIN(RADIANS(2*J2))*(0.019993-0.000101*G2)+SIN(RADIANS(3*J2))*0.00028
|
79
141
|
end
|
80
142
|
|
81
143
|
def self.true_longitude(julian_century)
|
@@ -90,8 +152,8 @@ module Sun
|
|
90
152
|
degrees(Math.asin(Math.sin(radians(oblique_correction)) * Math.sin(radians(apparent_longitude(julian_century)))))
|
91
153
|
end
|
92
154
|
|
93
|
-
def self.equation_of_time(
|
94
|
-
julian_century = julian_century(
|
155
|
+
def self.equation_of_time(date, longitude)
|
156
|
+
julian_century = julian_century(date)
|
95
157
|
oblique_correction = oblique_correction(julian_century)
|
96
158
|
geometric_mean_anomoly = geometric_mean_anomoly(julian_century)
|
97
159
|
geometric_mean_longitude = geometric_mean_longitude(julian_century)
|
@@ -100,22 +162,11 @@ module Sun
|
|
100
162
|
4 * degrees(y * Math.sin(2 * radians(geometric_mean_longitude)) - 2 * eccentricity_of_earth_orbit * Math.sin(radians(geometric_mean_anomoly)) + 4 * eccentricity_of_earth_orbit * y * Math.sin(radians(geometric_mean_anomoly)) * Math.cos(2 * radians(geometric_mean_longitude)) - 0.5 * y * y * Math.sin(4 * radians(geometric_mean_longitude)) - 1.25 * eccentricity_of_earth_orbit * eccentricity_of_earth_orbit * Math.sin(2 * radians(geometric_mean_anomoly)))
|
101
163
|
end
|
102
164
|
|
103
|
-
def self.hour_angle(
|
104
|
-
julian_century = julian_century(
|
165
|
+
def self.hour_angle(date, latitude)
|
166
|
+
julian_century = julian_century(date)
|
105
167
|
oblique_correction = oblique_correction(julian_century)
|
106
168
|
declination = declination(oblique_correction, julian_century)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
def self.solar_noon_minutes(time, latitude, longitude)
|
111
|
-
720 - (4 * longitude) - equation_of_time(time, longitude)
|
112
|
-
end
|
113
|
-
|
114
|
-
def self.sunrise_minutes(time, latitude, longitude)
|
115
|
-
solar_noon_minutes(time, latitude, longitude) - 4 * hour_angle(time, latitude)
|
116
|
-
end
|
117
|
-
|
118
|
-
def self.sunset_minutes(time, latitude, longitude)
|
119
|
-
solar_noon_minutes(time, latitude, longitude) + 4 * hour_angle(time, latitude)
|
169
|
+
res = Math.cos(radians(SOLAR_ZENITH)) / (Math.cos(radians(latitude)) * Math.cos(radians(declination))) - Math.tan(radians(latitude)) * Math.tan(radians(declination))
|
170
|
+
degrees(Math.acos(res))
|
120
171
|
end
|
121
172
|
end
|
data/lib/sun/version.rb
CHANGED
data/sun.gemspec
CHANGED
@@ -9,18 +9,10 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ['Cory Kaufman-Schofield']
|
10
10
|
spec.email = ['cory@corykaufman.com']
|
11
11
|
|
12
|
-
spec.summary = 'Calculate sunrise and sunset
|
12
|
+
spec.summary = 'Calculate sunrise and sunset times'
|
13
13
|
spec.homepage = 'https://github.com/allspiritseve/sun'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
|
-
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
17
|
-
# delete this section to allow pushing this gem to any host.
|
18
|
-
if spec.respond_to?(:metadata)
|
19
|
-
spec.metadata['allowed_push_host'] = 'http://mygemserver.com'
|
20
|
-
else
|
21
|
-
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
22
|
-
end
|
23
|
-
|
24
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^test/}) }
|
25
17
|
spec.bindir = 'exe'
|
26
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -31,5 +23,5 @@ Gem::Specification.new do |spec|
|
|
31
23
|
spec.add_development_dependency 'minitest'
|
32
24
|
spec.add_development_dependency 'minitest-reporters'
|
33
25
|
spec.add_development_dependency 'rake'
|
34
|
-
spec.add_development_dependency '
|
26
|
+
spec.add_development_dependency 'simplecov'
|
35
27
|
end
|
metadata
CHANGED
@@ -1,97 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sun
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cory Kaufman-Schofield
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: byebug
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: minitest
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: minitest-reporters
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: simplecov
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
description:
|
@@ -101,8 +101,8 @@ executables: []
|
|
101
101
|
extensions: []
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
|
-
- .gitignore
|
105
|
-
- .travis.yml
|
104
|
+
- ".gitignore"
|
105
|
+
- ".travis.yml"
|
106
106
|
- CODE_OF_CONDUCT.md
|
107
107
|
- Gemfile
|
108
108
|
- LICENSE.txt
|
@@ -110,32 +110,32 @@ files:
|
|
110
110
|
- Rakefile
|
111
111
|
- bin/console
|
112
112
|
- bin/setup
|
113
|
+
- circle.yml
|
113
114
|
- lib/sun.rb
|
114
115
|
- lib/sun/version.rb
|
115
116
|
- sun.gemspec
|
116
117
|
homepage: https://github.com/allspiritseve/sun
|
117
118
|
licenses:
|
118
119
|
- MIT
|
119
|
-
metadata:
|
120
|
-
allowed_push_host: http://mygemserver.com
|
120
|
+
metadata: {}
|
121
121
|
post_install_message:
|
122
122
|
rdoc_options: []
|
123
123
|
require_paths:
|
124
124
|
- lib
|
125
125
|
required_ruby_version: !ruby/object:Gem::Requirement
|
126
126
|
requirements:
|
127
|
-
- -
|
127
|
+
- - ">="
|
128
128
|
- !ruby/object:Gem::Version
|
129
129
|
version: '0'
|
130
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
131
|
requirements:
|
132
|
-
- -
|
132
|
+
- - ">="
|
133
133
|
- !ruby/object:Gem::Version
|
134
134
|
version: '0'
|
135
135
|
requirements: []
|
136
136
|
rubyforge_project:
|
137
|
-
rubygems_version: 2.
|
137
|
+
rubygems_version: 2.4.8
|
138
138
|
signing_key:
|
139
139
|
specification_version: 4
|
140
|
-
summary: Calculate sunrise and sunset
|
140
|
+
summary: Calculate sunrise and sunset times
|
141
141
|
test_files: []
|