sundial 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3@bobtime --create
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in sundial.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,77 @@
1
+ require './lib/sundial'
2
+ puts
3
+ puts
4
+
5
+ @s = Sundial.new
6
+
7
+ def printer(str)
8
+ print str, @s.send(str.strip.intern), "\n"
9
+ end
10
+
11
+ #
12
+ #@s.address = "201 West Broad Street, Richmond, VA"
13
+ #@s.address = "6526 Stuart Ave, Richmond, VA, 23226"
14
+ #@s.date = (Date.today + 110.days + 1.year).jd
15
+
16
+ #@s.address = "Amsterdam, Netherlands"
17
+ @s.address = @s.external_ip
18
+ #@s.date = Date.parse("2004-04-01").jd
19
+ #@s.date = Date.parse("2011-12-24").jd
20
+
21
+
22
+ #puts "lat_long", @s.lat_long
23
+
24
+ printer " latitude "
25
+ printer ' longitude '
26
+ printer ' longitude_west '
27
+ #printer ' get_offset '
28
+ printer 'get_timezone_offset '
29
+
30
+ puts "Driver Block One ----------------------"
31
+ printer " current_julian_date "
32
+ print " JULIAN_2000 ", "2451545", "\n"
33
+ printer ' jrd '
34
+ printer " current_julian_cycle "
35
+ printer ' solar_mean_anomaly '
36
+ printer " equation_of_center "
37
+ printer " ecliptic_longitude "
38
+ printer " right_ascension "
39
+ printer "declination_of_the_sun "
40
+ puts
41
+
42
+ puts "Driver Block Two ----------------------"
43
+ printer " l_sun "
44
+ printer " jpp "
45
+ printer " sunset_jd_two "
46
+ puts
47
+
48
+ puts "Driver Block Three ----------------------"
49
+ printer " sidereal_time "
50
+ printer " hour_angle "
51
+ printer " hour_angle_two "
52
+ printer "approximate_solar_noon "
53
+ printer " solar_transit "
54
+ puts
55
+
56
+ puts "Driver Block Four"
57
+ printer ' wiki_set '
58
+ printer ' sunrise_jd '
59
+ printer " sunset_jd "
60
+ printer " sunrise "
61
+ printer " sunset "
62
+ printer " sunrise_f "
63
+ printer " sunset_f "
64
+ printer ' length_of_day '
65
+ printer ' asn_date '
66
+
67
+ def format_datetime(dt)
68
+ dt.strftime("%B %e %Y %T")
69
+ end
70
+
71
+ puts "the equivalent of 9 AM on the solstice on this day would be", format_datetime(@s.nine)
72
+ puts "the equivalent of 5 pm on the solstice on this day would be", format_datetime(@s.five)
73
+
74
+
75
+
76
+
77
+ # Looks like the times are good, need to grab the timezone of the address being used and offset the UTC results by that much
@@ -0,0 +1,8 @@
1
+ class Numeric
2
+ def degrees
3
+ self * Math::PI / 180
4
+ end
5
+ def radians
6
+ self * 180 / Math::PI
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module Sundial
2
+ VERSION = "0.0.1"
3
+ end
data/lib/sundial.rb ADDED
@@ -0,0 +1,228 @@
1
+ require 'date'
2
+ require 'geokit'
3
+ require 'open-uri'
4
+ require 'json'
5
+ require 'active_support/time'
6
+
7
+ require_relative 'numeric_extensions'
8
+
9
+ class Sundial
10
+
11
+ attr_accessor :address, :date, :ip, :offset, :ll
12
+
13
+ def initialize
14
+ @address = "Richmond, Virginia"
15
+ end
16
+
17
+ JULIAN_2000 = 2451545
18
+
19
+ def local_time
20
+ DateTime.now
21
+ end
22
+
23
+ def whatismyip
24
+ "http://www.whatismyip.org/"
25
+ end
26
+
27
+ def current_julian_date
28
+ # http://stackoverflow.com/questions/5095456/using-the-ruby-date-class-for-astronomical-data
29
+ @date || Date.today.jd
30
+ end
31
+
32
+ def external_ip
33
+ @ip ||= open(whatismyip).read
34
+ @ip
35
+ # '75.75.82.80'
36
+ end
37
+
38
+ def lat_long
39
+ @ll ||= Geokit::Geocoders::MultiGeocoder.geocode(@address)
40
+ end
41
+
42
+ def longitude
43
+ lat_long.lng
44
+ end
45
+
46
+ def latitude
47
+ lat_long.lat
48
+ end
49
+
50
+ def longitude_west
51
+ -longitude
52
+ end
53
+
54
+
55
+
56
+ def get_offset
57
+ # see also http://www.hostip.info/
58
+ foo = open("http://www.earthtools.org/timezone-1.1/#{latitude}/#{longitude}").read
59
+ bar = foo.match(/<offset>(.*)<\/offset>/) if foo
60
+ if bar
61
+ @offset = bar[1].to_i
62
+ end
63
+ end
64
+
65
+ def get_timezone_offset
66
+ foo = open("http://www.askgeo.com/api/123016/vgdgoafgkvgdk6i9j26unjep4/timezone.json?points=#{latitude}%2C#{longitude}").read
67
+ bar = JSON.parse(foo)
68
+ if bar && bar['message'] == 'ok'
69
+ @offset = bar['data'].first['currentOffsetMs'].to_i / 3600000
70
+ end
71
+ end
72
+
73
+ def jrd
74
+ current_julian_date - JULIAN_2000
75
+ end
76
+
77
+ def current_julian_cycle
78
+ (current_julian_date - JULIAN_2000 - 0.0009 - (longitude_west / 360.0)).round
79
+ end
80
+
81
+
82
+ def solar_mean_anomaly # Mearth
83
+ # returns in degrees, 87.18
84
+ # Not sure if using approximate_solar_noon instead of current_julian_date is helpful or not
85
+ # Following this http://www.astro.uu.nl/~strous/AA/en/reken/zonpositie.html using current_julian_date
86
+ # ((357.5291 + 0.98560028 * (approximate_solar_noon - JULIAN_2000)) % 360).round(4) # this one is how wikipedia has it
87
+ ((357.5291 + 0.98560028 * (current_julian_date - JULIAN_2000)) % 360).round(4) # this on better for netherlands
88
+ end
89
+
90
+ def equation_of_center # Cearth
91
+ # returns in degrees 1.91
92
+ ((1.9148 * Math.sin(solar_mean_anomaly.degrees)) + (0.0200 * Math.sin((2 * solar_mean_anomaly).degrees)) + (0.0003 * Math.sin((3 * solar_mean_anomaly).degrees))).round(4)
93
+ end
94
+
95
+ def ecliptic_longitude # λsun
96
+ # returns in degrees 12.0321
97
+ # (solar_mean_anomaly + 102.9372 + 180) % 180
98
+ (solar_mean_anomaly + 102.9372 + equation_of_center + 180) % 360
99
+ end
100
+
101
+ def obliquity_of_the_equator # ε
102
+ 23.45
103
+ end
104
+
105
+ def l_sun
106
+ (solar_mean_anomaly + 102.9372 + 180) % 180
107
+ end
108
+
109
+ def sunset_jd_two
110
+ jpp + 0.0053 * Math.sin(solar_mean_anomaly.degrees) - 0.0069 * Math.sin((2 * l_sun).degrees)
111
+ end
112
+
113
+ def approximate_solar_noon # J(*)
114
+ (JULIAN_2000 + 0.0009 + (longitude_west / 360.0) + current_julian_cycle).round(4)
115
+ end
116
+
117
+ def asn_date
118
+ DateTime.jd(approximate_solar_noon)
119
+ end
120
+
121
+ def solar_transit
122
+ # Losing a lot of precision here :(
123
+ # not sure of these units, 2453097.0113
124
+ # 2453097.01224153
125
+ # (current_julian_date + (0.0053 * Math.sin(solar_mean_anomaly.degrees)) - (0.0069 * Math.sin((2 * ecliptic_longitude).degrees))).round(4)
126
+ (approximate_solar_noon + (0.0053 * Math.sin(solar_mean_anomaly.degrees)) - (0.0069 * Math.sin((2 * ecliptic_longitude).degrees))).round(4)
127
+ end
128
+
129
+ def declination_of_the_sun # δsun
130
+ # returns in degrees 4.7585
131
+ (Math.asin(Math.sin(ecliptic_longitude.degrees) * Math.sin(23.45.degrees))).round(5).radians
132
+ end
133
+
134
+
135
+ def right_ascension # αsun
136
+ (ecliptic_longitude + (-2.4680 * Math.sin((2 * ecliptic_longitude).degrees)) + (0.0530 * Math.sin((4 * ecliptic_longitude).degrees)) - (0.0014 * Math.sin((6 * ecliptic_longitude).degrees))).round(4)
137
+ end
138
+
139
+ def sidereal_time # θ
140
+ (((280.1600 + 360.9856235 * (current_julian_date - JULIAN_2000)) - (longitude_west)) % 360).round(4)
141
+ end
142
+
143
+ def hour_angle_two
144
+ sidereal_time - right_ascension
145
+ end
146
+
147
+ def hour_angle
148
+ # returns output in degrees
149
+ top = Math.sin(-0.83.degrees) - (Math.sin(latitude.degrees) * Math.sin(declination_of_the_sun.degrees))
150
+ bottom = Math.cos(latitude.degrees) * Math.cos(declination_of_the_sun.degrees)
151
+ tb = top / bottom
152
+ if((tb < -1.0) || (tb > 1.0))
153
+ return 0 # there is no sunrise or sunset on the given date for the given lat / long.
154
+ # Not sure what to return here, just hope for now that it doesn't happen.
155
+ end
156
+ # acos will blow up if input not in range (-1..1)
157
+ (Math.acos(tb).radians).round(4)
158
+ end
159
+
160
+ def jpp
161
+ JULIAN_2000 + 0.0009 + (hour_angle + (longitude_west)) * 1 / 360.0 + 1 * current_julian_cycle
162
+ end
163
+
164
+ def wiki_set # ends up close to sunset_jd, which is good i think
165
+ JULIAN_2000 + 0.0009 + (((hour_angle + (longitude_west)) / 360) + current_julian_cycle + 0.0053 * Math.sin(solar_mean_anomaly.degrees)) - 0.0069 * Math.sin((2 * ecliptic_longitude).degrees)
166
+ end
167
+
168
+ def sunset_jd
169
+ # puts "#{JULIAN_2000} + 0.0009 + (((#{hour_angle} + #{longitude}) / 360.0 ) + #{current_julian_cycle} + 0.0053 * Math.sin(#{solar_mean_anomaly})) - 0.0069 * Math.sin(2 * #{ecliptic_longitude})"
170
+ # foo = JULIAN_2000 + 0.0009 + (((hour_angle + longitude) / 360.0 ) + current_julian_cycle + 0.0053 * Math.sin(solar_mean_anomaly)) - 0.0069 * Math.sin(2 * ecliptic_longitude)
171
+ foo = jpp + 0.0053 * Math.sin(solar_mean_anomaly.degrees) - 0.0069 * Math.sin((2 * ecliptic_longitude).degrees)
172
+ foo.round(4)
173
+ end
174
+
175
+ def sunrise_jd
176
+ foo = solar_transit - (sunset_jd - solar_transit)
177
+ foo.round(4)
178
+ end
179
+
180
+ def sunset
181
+ foo = DateTime.jd(sunset_jd) + 12.hours
182
+ # foo = foo.new_offset(local_time.offset)
183
+ foo
184
+ end
185
+
186
+ def sunrise
187
+ foo = DateTime.jd(sunrise_jd) + 12.hours
188
+ # foo = foo.new_offset(local_time.offset)
189
+ foo
190
+ end
191
+
192
+ def sunrise_f
193
+ (sunrise + @offset.to_i.hours)
194
+ end
195
+
196
+ def sunset_f
197
+ (sunset + @offset.to_i.hours)
198
+ end
199
+
200
+ def length_of_day
201
+ (sunset - sunrise) * 24
202
+ end
203
+
204
+ def hour_ratio
205
+ length_of_day / 12.0
206
+ end
207
+
208
+ def nine
209
+ sunrise_f + (2 * hour_ratio).hours
210
+ end
211
+
212
+ def five
213
+ sunrise_f + (10 * hour_ratio).hours
214
+ end
215
+
216
+ def format_datetime(dt)
217
+ dt.strftime("%B %e %Y %T")
218
+ end
219
+
220
+
221
+
222
+
223
+
224
+ end
225
+
226
+
227
+
228
+ #Sundial.new.get_location
data/sundial.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "sundial/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "sundial"
7
+ s.version = Sundial::VERSION
8
+ s.authors = ["Bob Larrick"]
9
+ s.email = ["larrick@gmail.com"]
10
+ s.homepage = "https://github.com/deathbob/Sundial"
11
+ s.summary = %q{Gem to calculate the sunrise and sunset at your location}
12
+ s.description = %q{This gem calculates the sunrise and sunset at your current location.}
13
+
14
+ s.rubyforge_project = "sundial"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ s.add_runtime_dependency "activesupport"
24
+ s.add_runtime_dependency "geokit"
25
+
26
+ end
@@ -0,0 +1,121 @@
1
+ require 'minitest/autorun'
2
+
3
+ cal = File.join(File.dirname(__FILE__), '..', 'lib', 'sundial.rb')
4
+
5
+ puts File.exists? cal
6
+
7
+ require_relative File.join('..', 'lib', 'sundial')
8
+
9
+ class SunCalculatorTest < MiniTest::Unit::TestCase
10
+ def setup
11
+ @sc = Sundial.new
12
+ end
13
+
14
+ def test_local_time
15
+ assert @sc.local_time.to_i == DateTime.now.to_i
16
+ end
17
+
18
+ def test_julian_2000
19
+ assert Sundial::JULIAN_2000 == 2451545
20
+ end
21
+
22
+ def test_whatismyip
23
+ assert @sc.whatismyip == "http://www.whatismyip.org/"
24
+ end
25
+
26
+ describe Sundial do
27
+ before do
28
+ @sc = Sundial.new
29
+ end
30
+
31
+ describe 'current_julian_date' do
32
+ it 'should be today when no default is given' do
33
+ @sc.current_julian_date.must_equal Date.today.jd
34
+ end
35
+ it 'should be the default if default is given' do
36
+ cow = (Date.today - 1.days).jd
37
+ @sc.date = cow
38
+ @sc.current_julian_date.must_equal cow
39
+ end
40
+ end
41
+
42
+ describe 'address' do
43
+ # Address just needs to be something that can be geocoded.
44
+ it 'should default to my address' do
45
+ @sc.address.must_equal "Richmond, Virginia"
46
+ end
47
+
48
+ it 'should be whatever is given if set' do
49
+ cow = "71.1.2.3"
50
+ @sc.address = cow
51
+ @sc.address.must_equal cow
52
+ end
53
+ end
54
+
55
+ describe 'lat_long' do
56
+ before do
57
+ @latlng = Geokit::LatLng.new(37.5407246, -77.4360481)
58
+ @foo = Geokit::GeoLoc.new({:city =>'Richmond', :state => 'VA', :lat => @latlng.lat, :lng => @latlng.lng, :country_code => "US"})
59
+ end
60
+ # How to work VCR in here?
61
+ # it 'should geocode the default address' do
62
+ # @sc.lat_long.must_equal @foo
63
+ # end
64
+
65
+ describe 'given default address geocoded correctly' do
66
+ before do
67
+ @sc.ll = @foo
68
+ end
69
+ it 'should set latitude' do
70
+ @sc.latitude.must_be_close_to @latlng.lat
71
+ end
72
+ it 'should set longitude' do
73
+ @sc.longitude.must_be_close_to @latlng.lng
74
+ end
75
+ it 'should set the longitude_west to negative latitude' do
76
+ @sc.longitude_west.must_equal -@sc.longitude
77
+ end
78
+ describe "Getting the offset for the lat & lng" do
79
+ it 'should get_offset' do
80
+ @sc.get_offset.must_equal -5
81
+ @sc.offset.must_equal -5
82
+ end
83
+ it 'should get_timezone_offset' do
84
+ @sc.get_timezone_offset.must_equal -4
85
+ @sc.offset.must_equal -4
86
+ end
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ describe 'jrd' do
93
+ it 'should be the current_julian_date - JULIAN_2000' do
94
+ @sc.jrd.must_equal @sc.current_julian_date - Sundial::JULIAN_2000
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ end
101
+
102
+ # cloony
103
+
104
+ # expected_musts = %w(must_be
105
+ # must_be_close_to
106
+ # must_be_empty
107
+ # must_be_instance_of
108
+ # must_be_kind_of
109
+ # must_be_nil
110
+ # must_be_same_as
111
+ # must_be_silent
112
+ # must_be_within_delta
113
+ # must_be_within_epsilon
114
+ # must_equal
115
+ # must_include
116
+ # must_match
117
+ # must_output
118
+ # must_raise
119
+ # must_respond_to
120
+ # must_send
121
+ # must_throw)
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sundial
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Bob Larrick
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: &70204155777920 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70204155777920
25
+ - !ruby/object:Gem::Dependency
26
+ name: geokit
27
+ requirement: &70204155777420 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70204155777420
36
+ description: This gem calculates the sunrise and sunset at your current location.
37
+ email:
38
+ - larrick@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .rvmrc
44
+ - Gemfile
45
+ - Rakefile
46
+ - examples/driver.rb
47
+ - lib/numeric_extensions.rb
48
+ - lib/sundial.rb
49
+ - lib/sundial/version.rb
50
+ - sundial.gemspec
51
+ - test/sun_calculator_test.rb
52
+ homepage: https://github.com/deathbob/Sundial
53
+ licenses: []
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ requirements: []
71
+ rubyforge_project: sundial
72
+ rubygems_version: 1.8.15
73
+ signing_key:
74
+ specification_version: 3
75
+ summary: Gem to calculate the sunrise and sunset at your location
76
+ test_files:
77
+ - test/sun_calculator_test.rb