barometer 0.5.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +51 -9
- data/VERSION.yml +2 -2
- data/bin/barometer +57 -7
- data/lib/barometer.rb +11 -0
- data/lib/barometer/base.rb +3 -0
- data/lib/barometer/data.rb +11 -6
- data/lib/barometer/data/sun.rb +10 -0
- data/lib/barometer/data/zone.rb +79 -188
- data/lib/barometer/formats/coordinates.rb +4 -1
- data/lib/barometer/formats/geocode.rb +9 -7
- data/lib/barometer/formats/icao.rb +2 -2
- data/lib/barometer/formats/weather_id.rb +2 -2
- data/lib/barometer/measurements/common.rb +113 -0
- data/lib/barometer/{data → measurements}/current.rb +17 -42
- data/lib/barometer/measurements/forecast.rb +62 -0
- data/lib/barometer/measurements/forecast_array.rb +72 -0
- data/lib/barometer/{data → measurements}/measurement.rb +57 -45
- data/lib/barometer/measurements/night.rb +27 -0
- data/lib/barometer/query.rb +55 -5
- data/lib/barometer/services.rb +3 -1
- data/lib/barometer/translations/icao_country_codes.yml +274 -1
- data/lib/barometer/translations/weather_country_codes.yml +189 -6
- data/lib/barometer/translations/zone_codes.yml +360 -0
- data/lib/barometer/weather.rb +5 -4
- data/lib/barometer/weather_services/google.rb +19 -35
- data/lib/barometer/weather_services/service.rb +113 -255
- data/lib/barometer/weather_services/weather_bug.rb +291 -2
- data/lib/barometer/weather_services/weather_dot_com.rb +45 -54
- data/lib/barometer/weather_services/wunderground.rb +83 -89
- data/lib/barometer/weather_services/yahoo.rb +44 -91
- data/lib/barometer/web_services/geocode.rb +1 -0
- data/lib/barometer/web_services/timezone.rb +40 -0
- data/lib/barometer/web_services/weather_id.rb +17 -2
- data/lib/demometer/demometer.rb +28 -0
- data/lib/demometer/public/css/master.css +259 -1
- data/lib/demometer/public/css/print.css +94 -0
- data/lib/demometer/public/css/syntax.css +64 -0
- data/lib/demometer/public/images/link-out.gif +0 -0
- data/lib/demometer/views/about.erb +10 -0
- data/lib/demometer/views/index.erb +2 -0
- data/lib/demometer/views/layout.erb +3 -2
- data/lib/demometer/views/measurement.erb +4 -1
- data/lib/demometer/views/readme.erb +116 -88
- data/spec/data/sun_spec.rb +53 -0
- data/spec/data/zone_spec.rb +330 -100
- data/spec/fixtures/formats/weather_id/ksfo.xml +1 -0
- data/spec/fixtures/services/weather_bug/90210_current.xml +1 -0
- data/spec/fixtures/services/weather_bug/90210_forecast.xml +1 -0
- data/spec/formats/weather_id_spec.rb +10 -5
- data/spec/measurements/common_spec.rb +352 -0
- data/spec/{data → measurements}/current_spec.rb +40 -103
- data/spec/measurements/forecast_array_spec.rb +165 -0
- data/spec/measurements/forecast_spec.rb +135 -0
- data/spec/{data → measurements}/measurement_spec.rb +86 -107
- data/spec/measurements/night_measurement_spec.rb +49 -0
- data/spec/query_spec.rb +12 -2
- data/spec/spec_helper.rb +28 -1
- data/spec/weather_services/google_spec.rb +27 -117
- data/spec/weather_services/services_spec.rb +49 -1024
- data/spec/weather_services/weather_bug_spec.rb +274 -0
- data/spec/weather_services/weather_dot_com_spec.rb +45 -125
- data/spec/weather_services/wunderground_spec.rb +42 -136
- data/spec/weather_services/yahoo_spec.rb +26 -116
- data/spec/weather_spec.rb +45 -45
- metadata +27 -11
- data/lib/barometer/data/forecast.rb +0 -84
- data/lib/barometer/data/night.rb +0 -69
- data/lib/barometer/extensions/graticule.rb +0 -51
- data/spec/data/forecast_spec.rb +0 -192
- data/spec/data/night_measurement_spec.rb +0 -136
data/README.rdoc
CHANGED
@@ -10,25 +10,22 @@ unavailable.
|
|
10
10
|
|
11
11
|
Barometer handles all conversions of the supplied query, so that the
|
12
12
|
same query can be used for all (or most) services, even if they don't
|
13
|
-
support the query directly.
|
14
|
-
|
15
|
-
For example, Yahoo! only accepts US Zip Code or Weather.com ID. With Barometer
|
16
|
-
you can query Yahoo! with a simple location (ie: Paris) and it will return the
|
17
|
-
weather.
|
13
|
+
support the query directly. See the "Query" section for more information on
|
14
|
+
this.
|
18
15
|
|
19
16
|
== version
|
20
17
|
|
21
|
-
Version 0.
|
18
|
+
Version 0.6.0 is the current release of this gem.
|
22
19
|
The gem is available from github (attack-barometer) or rubyforge (barometer).
|
23
|
-
It is fully functional (for
|
20
|
+
It is fully functional (for five weather service APIs).
|
24
21
|
|
25
22
|
== status
|
26
23
|
|
27
24
|
Currently this project is in development and will only work for a few weather
|
28
|
-
services (wunderground, google, yahoo, weather.com).
|
25
|
+
services (wunderground, google, yahoo, weather.com, weather_bug).
|
29
26
|
|
30
27
|
Features to be added next:
|
31
|
-
- even more weather service drivers (noaa
|
28
|
+
- even more weather service drivers (noaa)
|
32
29
|
- icon support
|
33
30
|
|
34
31
|
= dependencies
|
@@ -59,6 +56,11 @@ eg. weather.com
|
|
59
56
|
partner: YOUR_PARTNER_KEY
|
60
57
|
license: YOUR_LICENSE_KEY
|
61
58
|
|
59
|
+
eg. weatherbug.com
|
60
|
+
|
61
|
+
weather_bug:
|
62
|
+
code: YOUR_API_CODE
|
63
|
+
|
62
64
|
== HTTParty
|
63
65
|
|
64
66
|
Why? HTTParty was created and designed specifically for consuming web services.
|
@@ -74,6 +76,45 @@ This information doesn't mean that much if it can't be converted to times
|
|
74
76
|
that don't correspond to the applicable timezone.
|
75
77
|
Tzinfo handles this time zone manipulation.
|
76
78
|
|
79
|
+
= queries
|
80
|
+
|
81
|
+
The query handling is one of the most beneficial and powerful features of
|
82
|
+
Barometer. Every weather service accepts a different set of possible
|
83
|
+
queries, so it usually the case that the same query can only be used
|
84
|
+
for a couple weather services.
|
85
|
+
|
86
|
+
Barometer will allow the use of all query formats for all services
|
87
|
+
(mostly). It does this by first determining the original query format,
|
88
|
+
then converting the query to a compatible format for each specific
|
89
|
+
weather service.
|
90
|
+
|
91
|
+
For example, Yahoo! only accepts US Zip Code or Weather.com ID. With Barometer
|
92
|
+
you can query Yahoo! with a simple location (ie: Paris) or even an Airport
|
93
|
+
code (ICAO) and it will return the weather as expected.
|
94
|
+
|
95
|
+
== acceptable formats
|
96
|
+
|
97
|
+
- zipcode
|
98
|
+
- icao (international airport code)
|
99
|
+
- coordinates (latitude and longitude)
|
100
|
+
- postal code
|
101
|
+
- weather.com ID
|
102
|
+
- location name (ie address, city, state, landmark, etc.)
|
103
|
+
|
104
|
+
* if the query is of the formats zipcode or postal code it may not
|
105
|
+
support conversion to other formats.
|
106
|
+
|
107
|
+
== conversion caching
|
108
|
+
|
109
|
+
Barometer has internal conversion caching. No conversion will be
|
110
|
+
repeated during a measurement, thus limiting the number of web queries
|
111
|
+
needed.
|
112
|
+
|
113
|
+
Example: If you configure Barometer to use both Yahoo and Weather.com,
|
114
|
+
then use a query like "denver", this will require a conversion from
|
115
|
+
"denver" to its weather.com weather_id. This conversion is needed for
|
116
|
+
both web services but will only happen once and be cached.
|
117
|
+
|
77
118
|
= usage
|
78
119
|
|
79
120
|
You can use barometer right out of the box, as it is configured to use one
|
@@ -99,6 +140,7 @@ The available sources are:
|
|
99
140
|
Yahoo! Weather (:yahoo)
|
100
141
|
Google Weather (:google)
|
101
142
|
Weather.com (:weather_dot_com)
|
143
|
+
WeatherBug.com (:weather_bug)
|
102
144
|
|
103
145
|
== source configuration
|
104
146
|
|
data/VERSION.yml
CHANGED
data/bin/barometer
CHANGED
@@ -29,12 +29,14 @@
|
|
29
29
|
# -V, --verbose Verbose output
|
30
30
|
# -t, --timeout seconds until service queries will timeout
|
31
31
|
# -g, --geocode Force Geocoding of query
|
32
|
+
# -z, --timezone Enhance Timezone
|
32
33
|
# -m, --metric measure in metric
|
33
34
|
# -i, --imperial measure in imperial
|
34
35
|
# --wunderground add wunderground as a source
|
35
36
|
# --yahoo add yahoo as a source
|
36
37
|
# --google add google as a source
|
37
38
|
# --weather add weather.com as a source
|
39
|
+
# --bug add weather_bug as a source
|
38
40
|
# -p, --pop pop threshold used to determine wet?
|
39
41
|
# -s, --wind wind speed threshold used to determine windy?
|
40
42
|
# -a, --at time/date used to determine when to calculate summary
|
@@ -64,7 +66,7 @@ require 'yaml'
|
|
64
66
|
|
65
67
|
# file where API keys are stored
|
66
68
|
KEY_FILE = File.expand_path(File.join('~', '.barometer'))
|
67
|
-
BAROMETER_VERSION = '0.
|
69
|
+
BAROMETER_VERSION = '0.6.0'
|
68
70
|
|
69
71
|
class App
|
70
72
|
|
@@ -77,6 +79,7 @@ class App
|
|
77
79
|
@options = OpenStruct.new
|
78
80
|
@options.timeout = 15
|
79
81
|
@options.geocode = false
|
82
|
+
@options.timezone = false
|
80
83
|
@options.metric = true
|
81
84
|
@options.sources = []
|
82
85
|
@options.verbode = false
|
@@ -120,12 +123,14 @@ class App
|
|
120
123
|
opt.on('-a n', '--at n') {|n| @options.at = Time.parse(n.to_s) }
|
121
124
|
opt.on('-t n', '--timeout n') {|n| @options.timeout = n }
|
122
125
|
opt.on('-g', '--geocode') { @options.geocode = true }
|
126
|
+
opt.on('-z', '--timezone') { @options.timezone = true }
|
123
127
|
opt.on('-m', '--metric') { @options.metric = true }
|
124
128
|
opt.on('-i', '--imperial') { @options.metric = false }
|
125
129
|
opt.on('--wunderground') { @options.sources << :wunderground; @options.default = false }
|
126
130
|
opt.on('--yahoo') { @options.sources << :yahoo; @options.default = false }
|
127
131
|
opt.on('--google') { @options.sources << :google; @options.default = false }
|
128
132
|
opt.on('--weather') { @options.sources << :weather_dot_com; @options.default = false }
|
133
|
+
opt.on('--bug') { @options.sources << :weather_bug; @options.default = false }
|
129
134
|
opt.on('-p n', '--pop n') {|n| @options.pop = n.to_i || 50 }
|
130
135
|
opt.on('-s n', '--wind n') {|n| @options.metric ? @options.windy_m = n.to_f || 10 : @options.windy_i = n.to_f || 7 }
|
131
136
|
|
@@ -157,16 +162,38 @@ class App
|
|
157
162
|
end
|
158
163
|
{ :weather_dot_com => { :keys => { :partner => partner_key, :license => license_key } } }
|
159
164
|
end
|
165
|
+
|
166
|
+
def config_weather_bug
|
167
|
+
if File.exists?(KEY_FILE)
|
168
|
+
keys = YAML.load_file(KEY_FILE)
|
169
|
+
if keys["weather_bug"] && keys["weather_bug"]["code"]
|
170
|
+
code = keys["weather_bug"]["code"].to_s
|
171
|
+
else
|
172
|
+
bug_key_message
|
173
|
+
exit
|
174
|
+
end
|
175
|
+
else
|
176
|
+
File.open(KEY_FILE, 'w') {|f| f << "\nweather_bug:\n code: API_CODE" }
|
177
|
+
bug_key_message
|
178
|
+
exit
|
179
|
+
end
|
180
|
+
{ :weather_bug => { :keys => { :code => code } } }
|
181
|
+
end
|
160
182
|
|
161
183
|
# Performs post-parse processing on options
|
162
184
|
def process_options
|
163
185
|
@options.sources << :wunderground if @options.default
|
164
186
|
@options.sources = @options.sources.uniq
|
165
187
|
Barometer.force_geocode = @options.geocode
|
188
|
+
Barometer.enhance_timezone = @options.timezone
|
166
189
|
if @options.sources.include?(:weather_dot_com)
|
167
190
|
@options.sources.delete(:weather_dot_com)
|
168
191
|
@options.sources << config_weather_dot_com
|
169
192
|
end
|
193
|
+
if @options.sources.include?(:weather_bug)
|
194
|
+
@options.sources.delete(:weather_bug)
|
195
|
+
@options.sources << config_weather_bug
|
196
|
+
end
|
170
197
|
Barometer.config = { 1 => @options.sources }
|
171
198
|
Barometer.timeout = @options.timeout
|
172
199
|
end
|
@@ -206,12 +233,14 @@ class App
|
|
206
233
|
puts " -V, --verbose Verbose output"
|
207
234
|
puts " -t, --timeout seconds until service queries will timeout"
|
208
235
|
puts " -g, --geocode Force Geocoding of query"
|
236
|
+
puts " -z, --timezone Force timezone query"
|
209
237
|
puts " -m, --metric measure in metric"
|
210
238
|
puts " -i, --imperial measure in imperial"
|
211
239
|
puts " --wunderground add wunderground as a source"
|
212
240
|
puts " --yahoo add yahoo as a source"
|
213
241
|
puts " --google add google as a source"
|
214
242
|
puts " --weather add weather.com as a source"
|
243
|
+
puts " --bug add weather_bug as a source"
|
215
244
|
puts " -p, --pop pop threshold used to determine wet?"
|
216
245
|
puts " -s, --wind wind speed threshold used to determine windy?"
|
217
246
|
puts " -a, --at time/date used to determine when to calculate summary"
|
@@ -232,7 +261,14 @@ class App
|
|
232
261
|
else
|
233
262
|
barometer = Barometer.new(@arguments.join(" "))
|
234
263
|
begin
|
264
|
+
if @options.verbose
|
265
|
+
Barometer::debug!
|
266
|
+
div(char="*")
|
267
|
+
puts "DEBUG LOG"
|
268
|
+
blank
|
269
|
+
end
|
235
270
|
barometer.measure(@options.metric) if barometer
|
271
|
+
blank if @options.verbose
|
236
272
|
pretty_output(barometer) if barometer.weather
|
237
273
|
rescue Barometer::OutOfSources
|
238
274
|
puts
|
@@ -292,8 +328,8 @@ def pretty_summary(s)
|
|
292
328
|
section("SUMMARY#{ " (@ #{@options.at})" if @options.at }") do
|
293
329
|
pretty_hash({
|
294
330
|
"day?" => s.day?(@options.at), "sunny?" => s.sunny?(@options.at),
|
295
|
-
"windy?" => s.windy?(@options.metric ? @options.windy_m : @options.windy_i
|
296
|
-
"wet?" => s.wet?(@options.
|
331
|
+
"windy?" => s.windy?(@options.at, @options.metric ? @options.windy_m : @options.windy_i),
|
332
|
+
"wet?" => s.wet?(@options.at, @options.pop) })
|
297
333
|
end
|
298
334
|
end
|
299
335
|
|
@@ -342,7 +378,8 @@ end
|
|
342
378
|
def pretty_timezone(t)
|
343
379
|
return unless t
|
344
380
|
section("TIMEZONE", 2) do
|
345
|
-
pretty_hash({ "Long" => t.
|
381
|
+
pretty_hash({ "Long" => t.full, "Code" => t.code, "DST?" => t.dst?,
|
382
|
+
"Now" => t.now(true), "Today" => t.today })
|
346
383
|
end
|
347
384
|
end
|
348
385
|
|
@@ -401,7 +438,8 @@ def pretty_measurement(m)
|
|
401
438
|
pretty_hash({
|
402
439
|
"Measured At" => m.measured_at,
|
403
440
|
"Source" => m.source, "Time Stamp" => m.utc_time_stamp,
|
404
|
-
"Metric" => m.metric?, "Success" => m.success
|
441
|
+
"Metric" => m.metric?, "Success" => m.success?,
|
442
|
+
"Service Time" => "#{(m.end_at - m.start_at)} s" })
|
405
443
|
end
|
406
444
|
section("MODIFIED QUERY", 2) do
|
407
445
|
pretty_hash({ "Query" => m.query, "Format" => m.format })
|
@@ -423,10 +461,11 @@ def pretty_measurements(w)
|
|
423
461
|
end
|
424
462
|
end
|
425
463
|
|
426
|
-
def pretty_info
|
464
|
+
def pretty_info(w)
|
427
465
|
title("INFO", 1)
|
428
466
|
value("GitHub", "http://github.com/attack/barometer")
|
429
467
|
value("Barometer Version", BAROMETER_VERSION)
|
468
|
+
value("Total Time", "#{(w.end_at - w.start_at)} s")
|
430
469
|
end
|
431
470
|
|
432
471
|
def pretty_output(barometer)
|
@@ -441,7 +480,7 @@ def pretty_output(barometer)
|
|
441
480
|
pretty_summary(weather)
|
442
481
|
pretty_query(barometer.query)
|
443
482
|
pretty_measurements(weather)
|
444
|
-
pretty_info
|
483
|
+
pretty_info(weather)
|
445
484
|
div("-")
|
446
485
|
end
|
447
486
|
end
|
@@ -481,6 +520,17 @@ def weather_key_message
|
|
481
520
|
puts
|
482
521
|
end
|
483
522
|
|
523
|
+
def bug_key_message
|
524
|
+
puts
|
525
|
+
puts "MISSING KEYS !!!"
|
526
|
+
puts "Please update the key_file '#{KEY_FILE}' with your weather_bug api key"
|
527
|
+
puts "Get it here: ???"
|
528
|
+
puts "Then, add these lines to the file:"
|
529
|
+
puts "weather_bug:"
|
530
|
+
puts " code: API_CODE"
|
531
|
+
puts
|
532
|
+
end
|
533
|
+
|
484
534
|
# set API keys
|
485
535
|
if File.exists?(KEY_FILE)
|
486
536
|
keys = YAML.load_file(KEY_FILE)
|
data/lib/barometer.rb
CHANGED
@@ -9,6 +9,12 @@ require 'barometer/formats'
|
|
9
9
|
|
10
10
|
module Barometer
|
11
11
|
|
12
|
+
@@debug_mode = false
|
13
|
+
def self.debug; @@debug_mode; end;
|
14
|
+
def self.debug=(value); @@debug_mode = value; end;
|
15
|
+
def self.debug!; @@debug_mode = true; end;
|
16
|
+
def self.debug?; @@debug_mode; end;
|
17
|
+
|
12
18
|
@@google_geocode_key = nil
|
13
19
|
def self.google_geocode_key; @@google_geocode_key; end;
|
14
20
|
def self.google_geocode_key=(key); @@google_geocode_key = key; end;
|
@@ -25,6 +31,11 @@ module Barometer
|
|
25
31
|
def self.force_geocode=(value); @@force_geocode = value; end;
|
26
32
|
def self.force_geocode!; @@force_geocode = true; end;
|
27
33
|
|
34
|
+
@@enhance_timezone = false
|
35
|
+
def self.enhance_timezone; @@enhance_timezone; end;
|
36
|
+
def self.enhance_timezone=(value); @@enhance_timezone = value; end;
|
37
|
+
def self.enhance_timezone!; @@enhance_timezone = true; end;
|
38
|
+
|
28
39
|
# adjust the timeout used when interactind with external web services
|
29
40
|
#
|
30
41
|
@@timeout = 15
|
data/lib/barometer/base.rb
CHANGED
@@ -22,6 +22,7 @@ module Barometer
|
|
22
22
|
#
|
23
23
|
def measure(metric=nil)
|
24
24
|
return nil unless @query
|
25
|
+
@weather.start_at = Time.now.utc
|
25
26
|
|
26
27
|
level = 1
|
27
28
|
until self.success?
|
@@ -32,6 +33,8 @@ module Barometer
|
|
32
33
|
end
|
33
34
|
level += 1
|
34
35
|
end
|
36
|
+
|
37
|
+
@weather.end_at = Time.now.utc
|
35
38
|
@weather
|
36
39
|
end
|
37
40
|
|
data/lib/barometer/data.rb
CHANGED
@@ -1,11 +1,7 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__))
|
2
2
|
|
3
|
-
#
|
3
|
+
# units
|
4
4
|
#
|
5
|
-
require 'data/measurement'
|
6
|
-
require 'data/current'
|
7
|
-
require 'data/forecast'
|
8
|
-
require 'data/night'
|
9
5
|
require 'data/zone'
|
10
6
|
require 'data/sun'
|
11
7
|
require 'data/geo'
|
@@ -16,4 +12,13 @@ require 'data/distance'
|
|
16
12
|
require 'data/speed'
|
17
13
|
require 'data/pressure'
|
18
14
|
require 'data/local_time'
|
19
|
-
require 'data/local_datetime'
|
15
|
+
require 'data/local_datetime'
|
16
|
+
|
17
|
+
# measurements
|
18
|
+
#
|
19
|
+
require 'measurements/measurement'
|
20
|
+
require 'measurements/common'
|
21
|
+
require 'measurements/current'
|
22
|
+
require 'measurements/forecast_array'
|
23
|
+
require 'measurements/forecast'
|
24
|
+
require 'measurements/night'
|
data/lib/barometer/data/sun.rb
CHANGED
@@ -18,6 +18,16 @@ module Barometer
|
|
18
18
|
def nil?
|
19
19
|
(@rise || @set) ? false : true
|
20
20
|
end
|
21
|
+
|
22
|
+
def after_rise?(time)
|
23
|
+
raise ArgumentError unless time.is_a?(Data::LocalTime)
|
24
|
+
time >= @rise
|
25
|
+
end
|
21
26
|
|
27
|
+
def before_set?(time)
|
28
|
+
raise ArgumentError unless time.is_a?(Data::LocalTime)
|
29
|
+
time <= @set
|
30
|
+
end
|
31
|
+
|
22
32
|
end
|
23
33
|
end
|
data/lib/barometer/data/zone.rb
CHANGED
@@ -11,19 +11,49 @@ module Barometer
|
|
11
11
|
#
|
12
12
|
class Data::Zone
|
13
13
|
|
14
|
-
|
14
|
+
@@zone_codes_file = File.expand_path(
|
15
|
+
File.join(File.dirname(__FILE__), '..', 'translations', 'zone_codes.yml'))
|
16
|
+
@@zone_codes = nil
|
17
|
+
|
18
|
+
attr_accessor :zone_full, :zone_code, :zone_offset, :tz
|
19
|
+
|
20
|
+
def initialize(zone)
|
21
|
+
if Data::Zone.is_zone_full?(zone)
|
22
|
+
@zone_full = zone
|
23
|
+
@tz = TZInfo::Timezone.get(zone)
|
24
|
+
elsif Data::Zone.is_zone_offset?(zone)
|
25
|
+
@zone_offset = zone
|
26
|
+
elsif Data::Zone.is_zone_code?(zone)
|
27
|
+
@zone_code = zone
|
28
|
+
else
|
29
|
+
raise(ArgumentError, "invalid time zone")
|
30
|
+
end
|
31
|
+
end
|
15
32
|
|
16
|
-
def
|
17
|
-
@
|
18
|
-
@tz = TZInfo::Timezone.get(timezone)
|
33
|
+
def current
|
34
|
+
@zone_full || @zone_offset || @zone_code
|
19
35
|
end
|
20
36
|
|
21
37
|
# what is the Timezone Short Code for the current timezone
|
22
38
|
def code
|
23
|
-
return
|
39
|
+
return @zone_code if @zone_code
|
40
|
+
return nil unless @tz
|
24
41
|
@tz.period_for_utc(Time.now.utc).zone_identifier.to_s
|
25
42
|
end
|
26
43
|
|
44
|
+
def full
|
45
|
+
@zone_full || nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def offset
|
49
|
+
if @zone_offset
|
50
|
+
@zone_offset.to_f * 60 * 60
|
51
|
+
elsif @zone_code
|
52
|
+
Data::Zone.zone_to_offset(@zone_code)
|
53
|
+
elsif @zone_full
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
27
57
|
# is the current timezone in daylights savings mode?
|
28
58
|
def dst?
|
29
59
|
return nil unless @tz
|
@@ -31,98 +61,59 @@ module Barometer
|
|
31
61
|
end
|
32
62
|
|
33
63
|
# return Time.now.utc for the set timezone
|
34
|
-
def now
|
35
|
-
|
64
|
+
def now(convert=false)
|
65
|
+
if @zone_full
|
66
|
+
now = @tz.utc_to_local(Time.now.utc)
|
67
|
+
elsif @zone_offset || @zone_code
|
68
|
+
now = Time.now.utc + self.offset
|
69
|
+
end
|
70
|
+
convert ? Data::LocalTime.parse(now) : now
|
36
71
|
end
|
37
72
|
|
38
73
|
# return Date.today for the set timezone
|
39
74
|
def today
|
40
|
-
|
75
|
+
now = self.now
|
76
|
+
Date.new(now.year, now.month, now.day)
|
41
77
|
end
|
42
78
|
|
43
79
|
def local_to_utc(local_time)
|
44
|
-
@
|
80
|
+
if @zone_full
|
81
|
+
@tz.local_to_utc(local_time)
|
82
|
+
elsif @zone_offset || @zone_code
|
83
|
+
local_time -= self.offset
|
84
|
+
Time.utc(local_time.year,local_time.month,local_time.day,
|
85
|
+
local_time.hour,local_time.min,local_time.sec)
|
86
|
+
end
|
45
87
|
end
|
46
88
|
|
47
89
|
def utc_to_local(utc_time)
|
48
|
-
@
|
90
|
+
if @zone_full
|
91
|
+
@tz.utc_to_local(utc_time)
|
92
|
+
elsif @zone_offset || @zone_code
|
93
|
+
utc_time + self.offset
|
94
|
+
end
|
49
95
|
end
|
50
96
|
|
51
97
|
#
|
52
98
|
# Class Methods
|
53
99
|
#
|
54
100
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
if timezone
|
60
|
-
utc = Time.now.utc
|
61
|
-
tz = TZInfo::Timezone.get(timezone)
|
62
|
-
tz.utc_to_local(utc)
|
63
|
-
else
|
64
|
-
Time.now
|
65
|
-
end
|
101
|
+
def self.is_zone_code?(zone)
|
102
|
+
return false unless (zone && zone.is_a?(String))
|
103
|
+
_load_zone_codes unless @@zone_codes
|
104
|
+
Time.zone_offset(zone) || (@@zone_codes && @@zone_codes.has_key?(zone))
|
66
105
|
end
|
67
106
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
def self.today(timezone=nil)
|
72
|
-
if timezone
|
73
|
-
utc = Time.now.utc
|
74
|
-
tz = TZInfo::Timezone.get(timezone)
|
75
|
-
now = tz.utc_to_local(utc)
|
76
|
-
Date.new(now.year, now.month, now.day)
|
77
|
-
else
|
78
|
-
Date.today
|
79
|
-
end
|
107
|
+
def self.is_zone_full?(zone)
|
108
|
+
return false unless (zone && zone.is_a?(String))
|
109
|
+
zone.match(/[A-Za-z]+\/[A-Za-z]+/) ? true : false
|
80
110
|
end
|
81
111
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
# NOTE: No Tests
|
86
|
-
def self.code_to_utc(time, timezone)
|
87
|
-
raise ArgumentError unless time.is_a?(Time)
|
88
|
-
|
89
|
-
offset = self.zone_to_offset(timezone)
|
90
|
-
|
91
|
-
Time.utc(
|
92
|
-
time.year, time.month, time.day,
|
93
|
-
time.hour, time.min, time.sec, time.usec
|
94
|
-
) - offset
|
95
|
-
end
|
96
|
-
|
97
|
-
# takes a string with TIME only information and merges it with a string that
|
98
|
-
# has DATE only information and creates a UTC TIME object with time and date
|
99
|
-
# info. if you supply the timezone code (ie PST), it will apply the timezone
|
100
|
-
# offset to the final time
|
101
|
-
def self.merge(time, date, timezone_code=nil)
|
102
|
-
raise ArgumentError unless (time.is_a?(Time) || time.is_a?(String))
|
103
|
-
raise ArgumentError unless (date.is_a?(Time) || date.is_a?(Date) || date.is_a?(String))
|
104
|
-
|
105
|
-
if time.is_a?(String)
|
106
|
-
reference_time = Time.parse(time)
|
107
|
-
elsif time.is_a?(Time)
|
108
|
-
reference_time = time
|
109
|
-
end
|
110
|
-
|
111
|
-
if date.is_a?(String)
|
112
|
-
reference_date = Date.parse(date)
|
113
|
-
elsif date.is_a?(Time)
|
114
|
-
reference_date = Date.new(date.year, date.month, date.day)
|
115
|
-
elsif date.is_a?(Date)
|
116
|
-
reference_date = date
|
117
|
-
end
|
118
|
-
|
119
|
-
new_time = Time.utc(
|
120
|
-
reference_date.year, reference_date.month, reference_date.day,
|
121
|
-
reference_time.hour, reference_time.min, reference_time.sec
|
122
|
-
)
|
123
|
-
timezone_code ? Data::Zone.code_to_utc(new_time,timezone_code) : new_time
|
112
|
+
def self.is_zone_offset?(zone)
|
113
|
+
return false unless (zone && (zone.is_a?(Fixnum) || zone.is_a?(Float)))
|
114
|
+
zone.to_f.abs <= 14
|
124
115
|
end
|
125
|
-
|
116
|
+
|
126
117
|
#
|
127
118
|
# Known conflicts
|
128
119
|
# IRT (ireland and india)
|
@@ -131,119 +122,19 @@ module Barometer
|
|
131
122
|
def self.zone_to_offset(timezone)
|
132
123
|
offset = 0
|
133
124
|
seconds_in_hour = 60*60
|
134
|
-
#
|
135
|
-
|
136
|
-
|
137
|
-
#
|
138
|
-
|
139
|
-
|
140
|
-
# try to use Time
|
141
|
-
unless offset = Time.zone_offset(timezone)
|
142
|
-
# that would have been too easy, do it manually
|
143
|
-
# http://www.timeanddate.com/library/abbreviations/timezones/
|
144
|
-
# http://www.worldtimezone.com/wtz-names/timezonenames.html
|
145
|
-
zone_offsets = {
|
146
|
-
:A => 1, :ACDT => 10.5, :ACST => 9.5, :ADT => -3, :AEDT => 11,
|
147
|
-
:AEST => 10, :AFT => 4.5, :AHDT => -9, :AHST => -10, :AKDT => -8,
|
148
|
-
:AKST => -9, :AMST => 5, :AMT => 4, :ANAST => 13, :ANAT => 12,
|
149
|
-
:ART => -3, :AST => -4, :AT => -1, :AWDT => 9, :AWST => 8,
|
150
|
-
:AZOST => 0, :AZOT => -1, :AZST => 5, :AZT => 4,
|
151
|
-
|
152
|
-
:B => 2, :BADT => 4, :BAT => 6, :BDST => 2, :BDT => 6, :BET => -11,
|
153
|
-
:BNT => 8, :BORT => 8, :BOT => -4, :BRA => -3, :BST => 1, :BT => 6,
|
154
|
-
:BTT => 6,
|
155
|
-
|
156
|
-
:C => 3, :CAT => 2, :CCT => 8, :CEST => 2, :CET => 1, :CHADT => 13.75,
|
157
|
-
:CHAST => 12.75, :CHST => 10, :CKT => -10, :CLST => -3, :CLT => -4,
|
158
|
-
:COT => -5, :CUT => 0, :CVT => -1, :CWT => 8.75, :CXT => 7, :CEDT => 2,
|
159
|
-
|
160
|
-
:D => 4, :DAVT => 7, :DDUT => 10, :DNT => 1, :DST => 2,
|
161
|
-
|
162
|
-
:E => 5, :EASST => -5, :EAST => -6, :EAT => 3, :ECT => -5, :EEST => 3,
|
163
|
-
:EET => 2, :EGST => 0, :EGT => -1, :EMT => 1, :EEDT => 3,
|
164
|
-
|
165
|
-
:F => 6, :FDT => -1, :FJST => 13, :FJT => 12, :FKST => -3, :FKT => -4,
|
166
|
-
:FST => 2, :FWT => 1,
|
167
|
-
|
168
|
-
:G => 7, :GALT => -6, :GAMT => -9, :GEST => 5, :GET => 4, :GFT => -3,
|
169
|
-
:GILT => 12, :GST => 4, :GT => 0, :GYT => -4, :GZ => 0,
|
170
|
-
|
171
|
-
:H => 8, :HAA => -3, :HAC => -5, :HADT => -9, :HAE => -4, :HAP => -7,
|
172
|
-
:HAR => -6, :HAST => -10, :HAT => -2.5, :HAY => -8, :HDT => -9.5,
|
173
|
-
:HFE => 2, :HFH => 1, :HG => 0, :HKT => 8, :HNA => -4, :HNC => -6,
|
174
|
-
:HNE => -5, :HNP => -8, :HNR => -7, :HNT => -3.5, :HNY => -9,
|
175
|
-
:HOE => 1, :HST => -10,
|
176
|
-
|
177
|
-
:I => 9, :ICT => 4, :IDLE => 12, :IDLW => -12, :IDT => 1, :IOT => 5,
|
178
|
-
:IRDT => 4.5, :IRKST => 9, :IRKT => 8, :IRST => 3.5, :IRT => 3.5,
|
179
|
-
:IST => 1, :IT => 3.5, :ITA => 1,
|
180
|
-
|
181
|
-
:JAVT => 7, :JAYT => 9, :JFDT => -3, :JFST => -4, :JST => 9, :JT => 7,
|
182
|
-
|
183
|
-
:K => 10, :KDT => 10, :KGST => 6, :KGT => 5, :KOST => 12, :KOVT => 7,
|
184
|
-
:KOVST => 8, :KRAST => 8, :KRAT => 7, :KST => 9,
|
185
|
-
|
186
|
-
:L => 11, :LHDT => 11, :LHST => 10.5, :LIGT => 10, :LINT => 14, :LKT => 6,
|
187
|
-
:LST => 1,
|
188
|
-
|
189
|
-
:M => 12, :MAGST => 12, :MAGT => 11, :MAL => 8, :MART => -9.5, :MAT => 3,
|
190
|
-
:MAWT => 6, :MBT => 8, :MED => 2, :MEDST => 2, :MEST => 2, :MESZ => 2,
|
191
|
-
:MET => 1, :MEWT => 1, :MEX => -6, :MEZ => 1, :MHT => 12, :MIT => 9.5,
|
192
|
-
:MMT => 6.5, :MNT => 8, :MNST => 9, :MPT => 10, :MSD => 4, :MSK => 3,
|
193
|
-
:MSKS => 4, :MT => 8.5, :MUT => 4, :MUST => 5, :MVT => 5, :MYT => 8,
|
194
|
-
:MFPT => -10,
|
195
|
-
|
196
|
-
:N => -1, :NCT => 11, :NDT => -2.5, :NFT => 11.5, :NOR => 1, :NOVST => 7,
|
197
|
-
:NOVT => 6, :NPT => 5.75, :NRT => 12, :NST => -3.5, :NSUT => 6.5,
|
198
|
-
:NT => -11, :NUT => -11, :NZDT => 13, :NZST => 12, :NZT => 12,
|
199
|
-
|
200
|
-
:O => -2, :OESZ => 3, :OEZ => 2, :OMSK => 7, :OMSST => 7, :OMST => 6,
|
201
|
-
|
202
|
-
:P => -3, :PET => -5, :PETST => 13, :PETT => 12, :PGT => 10, :PHOT => 13,
|
203
|
-
:PHT => 8, :PIT => 8, :PKT => 5, :PKST => 6, :PMDT => -2, :PMST => -3,
|
204
|
-
:PMT => -3, :PNT => -8.5, :PONT => 11, :PYST => -3, :PYT => -4, :PWT => 9,
|
205
|
-
|
206
|
-
:Q => -4,
|
207
|
-
|
208
|
-
:R => -5, :R1T => 2, :R2T => 3, :RET => 4, :ROK => 9, :ROTT => -3,
|
209
|
-
|
210
|
-
:S => -6, :SADT => 10.5, :SAMST => 5, :SAMT => 4, :SAST => 2, :SBT => 11,
|
211
|
-
:SCT => 4, :SCDT => 13, :SCST => 12, :SET => 1, :SGT => 8, :SIT => 8,
|
212
|
-
:SLT => -4, :SLST => -3, :SRT => -3, :SST => -11, :SYST => 3, :SWT => 1,
|
213
|
-
:SYT => 2,
|
214
|
-
|
215
|
-
:T => -7, :TAHT => -10, :TFT => 5, :THA => 7, :THAT => -10, :TJT => 5,
|
216
|
-
:TKT => -10, :TMT => 5, :TOT => 13, :TRUK => 10, :TPT => 9, :TRUT => 10,
|
217
|
-
:TST => 3, :TUC => 0, :TVT => 12, :TWT => 8,
|
218
|
-
|
219
|
-
:U => -8, :ULAST => 9, :ULAT => 8, :USZ1 => 2, :USZ1S => 3, :USZ3 => 4,
|
220
|
-
:USZ3S => 5, :USZ4 => 5, :USZ4S => 6, :USZ5 => 6, :USZ5S => 7, :USZ6 => 7,
|
221
|
-
:USZ6S => 8, :USZ7 => 8, :USZ7S => 9, :USZ8 => 9, :USZ8S => 10, :USZ9 => 10,
|
222
|
-
:USZ9S => 11, :UTZ => -3, :UYT => -3, :UYST => -2, :UZ10 => 11, :UZ10S => 12,
|
223
|
-
:UZ11 => 12, :UZ11S => 13, :UZ12 => 12, :UZ12S => 13, :UZT => 5,
|
224
|
-
|
225
|
-
:V => -9, :VET => -4.5, :VLAST => 11, :VLAT => 10, :VOST => 6, :VST => -4.5,
|
226
|
-
:VTZ => -2, :VUT => 11,
|
227
|
-
|
228
|
-
:W => -10, :WAKT => 12, :WAST => 2, :WAT => 1, :WCT => 8.75, :WEST => 1,
|
229
|
-
:WESZ => 1, :WET => 0, :WEZ => 0, :WFT => 12, :WGST => -2, :WGT => -3,
|
230
|
-
:WIB => 7, :WITA => 8, :WIT => 9, :WST => 8, :WKST => 5, :WTZ => -1,
|
231
|
-
:WUT => 1, :WEDT => 1, :WDT => 9,
|
232
|
-
|
233
|
-
:X => -11,
|
234
|
-
|
235
|
-
:Y => -12, :YAKST => 10, :YAKT => 9, :YAPT => 10, :YDT => -8, :YEKST => 6,
|
236
|
-
:YEKT => 5, :YST => -9,
|
237
|
-
|
238
|
-
:Z => 0
|
239
|
-
}
|
240
|
-
# unknown
|
241
|
-
# :HL => X, :LST => X, :LT => X, :OZ => X :SZ => X :TAI => X :UT => X :WZ => X
|
242
|
-
|
243
|
-
offset = (zone_offsets[timezone.to_s.upcase.to_sym] || 0) * seconds_in_hour
|
244
|
-
end
|
125
|
+
# try to use Time
|
126
|
+
unless offset = Time.zone_offset(timezone)
|
127
|
+
# that would have been too easy, do it manually
|
128
|
+
# http://www.timeanddate.com/library/abbreviations/timezones/
|
129
|
+
# http://www.worldtimezone.com/wtz-names/timezonenames.html
|
130
|
+
offset = (@@zone_codes[timezone.to_s.upcase] || 0) * seconds_in_hour
|
245
131
|
end
|
246
|
-
|
132
|
+
offset
|
133
|
+
end
|
134
|
+
|
135
|
+
def self._load_zone_codes
|
136
|
+
$:.unshift(File.dirname(__FILE__))
|
137
|
+
@@zone_codes ||= YAML.load_file(@@zone_codes_file)
|
247
138
|
end
|
248
139
|
|
249
140
|
end
|