timezone 0.6.0 → 0.99.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +99 -1
- data/.travis.yml +6 -3
- data/CHANGES.markdown +10 -0
- data/Gemfile +1 -1
- data/README.markdown +129 -89
- data/Rakefile +7 -4
- data/benchmark.rb +13 -13
- data/lib/timezone/active_support.rb +147 -134
- data/lib/timezone/configure.rb +131 -110
- data/lib/timezone/deprecate.rb +32 -0
- data/lib/timezone/error.rb +16 -5
- data/lib/timezone/loader.rb +19 -16
- data/lib/timezone/lookup/basic.rb +24 -2
- data/lib/timezone/lookup/geonames.rb +9 -5
- data/lib/timezone/lookup/google.rb +24 -15
- data/lib/timezone/lookup/test.rb +8 -8
- data/lib/timezone/lookup.rb +68 -0
- data/lib/timezone/net_http_client.rb +23 -9
- data/lib/timezone/nil_zone.rb +32 -0
- data/lib/timezone/parser.rb +10 -5
- data/lib/timezone/version.rb +2 -1
- data/lib/timezone/zone.rb +230 -99
- data/lib/timezone.rb +75 -1
- data/test/basic_lookup_test.rb +2 -2
- data/test/geonames_lookup_test.rb +13 -6
- data/test/google_lookup_test.rb +34 -24
- data/test/http_test_client.rb +7 -6
- data/test/test_lookup_test.rb +3 -1
- data/test/test_timezone.rb +59 -0
- data/test/timezone/lookup/test_geonames.rb +59 -0
- data/test/timezone/lookup/test_google.rb +94 -0
- data/test/timezone/lookup/test_test.rb +24 -0
- data/test/timezone/test_deprecate.rb +20 -0
- data/test/timezone/test_loader.rb +32 -0
- data/test/timezone/test_lookup.rb +53 -0
- data/test/timezone/test_nil_zone.rb +26 -0
- data/test/timezone/test_zone.rb +49 -0
- data/test/timezone_test.rb +64 -63
- data/timezone.gemspec +16 -15
- metadata +39 -38
- data/.rubocop_todo.yml +0 -235
data/lib/timezone/zone.rb
CHANGED
@@ -6,144 +6,267 @@ require 'timezone/loader'
|
|
6
6
|
require 'timezone/error'
|
7
7
|
require 'timezone/configure'
|
8
8
|
require 'timezone/active_support'
|
9
|
+
require 'timezone/loader'
|
10
|
+
require 'timezone/deprecate'
|
9
11
|
|
10
12
|
module Timezone
|
13
|
+
# This object represents a real-world timezone. Each instance provides
|
14
|
+
# methods for converting UTC times to the local timezone and local
|
15
|
+
# times to UTC for any historical, present or future times.
|
11
16
|
class Zone
|
12
17
|
include Comparable
|
13
|
-
|
18
|
+
|
19
|
+
# @return [String] the timezone name
|
20
|
+
attr_reader :name
|
21
|
+
|
22
|
+
alias to_s name
|
23
|
+
|
24
|
+
# @return [String] a developer friendly representation of the object
|
25
|
+
def inspect
|
26
|
+
"#<Timezone::Zone name: \"#{name}\">"
|
27
|
+
end
|
28
|
+
|
29
|
+
# If this is a valid timezone.
|
30
|
+
#
|
31
|
+
# @return [true] if this is a valid timezone
|
32
|
+
def valid?
|
33
|
+
true
|
34
|
+
end
|
14
35
|
|
15
36
|
SOURCE_BIT = 0
|
37
|
+
private_constant :SOURCE_BIT
|
16
38
|
NAME_BIT = 1
|
39
|
+
private_constant :NAME_BIT
|
17
40
|
DST_BIT = 2
|
41
|
+
private_constant :DST_BIT
|
18
42
|
OFFSET_BIT = 3
|
43
|
+
private_constant :OFFSET_BIT
|
19
44
|
|
20
|
-
# Create a new
|
21
|
-
#
|
22
|
-
# Timezone.new(options)
|
45
|
+
# Create a new timezone object using the timezone name.
|
23
46
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
47
|
+
# @param name [String] the timezone name
|
48
|
+
# @return [Timezone::Zone]
|
49
|
+
def initialize(name)
|
50
|
+
if name.is_a?(Hash)
|
51
|
+
legacy_initialize(name)
|
52
|
+
else
|
53
|
+
@name = name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @deprecated This method will be replaced with `Zone#name` in
|
58
|
+
# future versions of this gem.
|
59
|
+
def zone
|
60
|
+
Deprecate.call(
|
61
|
+
self.class,
|
62
|
+
:zone,
|
63
|
+
'[DEPRECATED] `Zone#zone` will not be available in ' \
|
64
|
+
'the next release of the `timezone` gem. Use `Zone#name` ' \
|
65
|
+
'instead.'.freeze
|
66
|
+
)
|
67
|
+
|
68
|
+
name
|
69
|
+
end
|
70
|
+
|
71
|
+
# @deprecated This method will be removed in the next release.
|
72
|
+
def rules
|
73
|
+
Deprecate.call(
|
74
|
+
self.class,
|
75
|
+
:rules,
|
76
|
+
'[DEPRECATED] `Zone#rules` will not be available in ' \
|
77
|
+
'the next release of the `timezone` gem.'.freeze
|
78
|
+
)
|
79
|
+
|
80
|
+
private_rules
|
81
|
+
end
|
82
|
+
|
83
|
+
# @deprecated This functionality only exists for migration purposes.
|
84
|
+
def legacy_initialize(options)
|
85
|
+
Deprecate.call(
|
86
|
+
self.class,
|
87
|
+
:initialize,
|
88
|
+
'[DEPRECATED] Creating Zone objects using an options hash ' \
|
89
|
+
'will be deprecated in the next release of the `timezone` ' \
|
90
|
+
'gem. Use `Timezone::[]`, `Timezone::fetch` or ' \
|
91
|
+
'`Timezone::lookup` instead.'.freeze
|
92
|
+
)
|
93
|
+
|
94
|
+
if options.key?(:lat) && options.key?(:lon)
|
33
95
|
options[:zone] = timezone_id options[:lat], options[:lon]
|
34
|
-
elsif options.
|
96
|
+
elsif options.key?(:latlon)
|
35
97
|
options[:zone] = timezone_id(*options[:latlon])
|
36
98
|
end
|
37
99
|
|
38
|
-
|
100
|
+
if options[:zone].nil?
|
101
|
+
raise Timezone::Error::NilZone,
|
102
|
+
'No zone was found. Please specify a zone.'.freeze
|
103
|
+
end
|
39
104
|
|
40
|
-
@
|
41
|
-
|
105
|
+
@name = options[:zone]
|
106
|
+
private_rules
|
42
107
|
end
|
43
108
|
|
109
|
+
# @deprecated This functionality will be removed in the next release.
|
44
110
|
def active_support_time_zone
|
45
|
-
|
111
|
+
Deprecate.call(
|
112
|
+
self.class,
|
113
|
+
:active_support_time_zone,
|
114
|
+
'[DEPRECATED] `Zone#active_support_time_zone` will be ' \
|
115
|
+
'deprecated in the next release of the `timezone` gem. There ' \
|
116
|
+
'will be no replacement.'.freeze
|
117
|
+
)
|
118
|
+
|
119
|
+
@active_support_time_zone ||=
|
120
|
+
Timezone::ActiveSupport.format(name, :internal)
|
46
121
|
end
|
47
122
|
|
48
|
-
#
|
49
|
-
#
|
50
|
-
# timezone.time(reference)
|
123
|
+
# Converts the given time to the local timezone and does not include
|
124
|
+
# a UTC offset in the result.
|
51
125
|
#
|
52
|
-
#
|
126
|
+
# @param time [#to_time] the source time
|
127
|
+
# @return [Time] the time in the local timezone
|
53
128
|
#
|
54
|
-
# The
|
55
|
-
#
|
56
|
-
#
|
57
|
-
def time
|
58
|
-
|
129
|
+
# @note The resulting time is always a UTC time. If you would like
|
130
|
+
# a time with the appropriate offset, use `#time_with_offset`
|
131
|
+
# instead.
|
132
|
+
def utc_to_local(time)
|
133
|
+
time = sanitize(time)
|
59
134
|
|
60
|
-
|
135
|
+
time.utc + utc_offset(time)
|
61
136
|
end
|
62
137
|
|
63
|
-
alias utc_to_local
|
138
|
+
alias time utc_to_local
|
64
139
|
|
65
|
-
#
|
140
|
+
# Converts the given local time to the UTC equivalent.
|
141
|
+
#
|
142
|
+
# @param time [#to_time] the local time
|
143
|
+
# @return [Time] the time in UTC
|
144
|
+
#
|
145
|
+
# @note The UTC equivalent is a "best guess". There are cases where
|
146
|
+
# local times do not map to UTC at all (during a time skip forward).
|
147
|
+
# There are also cases where local times map to two distinct UTC
|
148
|
+
# times (during a fall back). All of these cases are approximated
|
149
|
+
# in this method and the first possible result is used instead.
|
66
150
|
#
|
67
|
-
#
|
151
|
+
# @note A note about the handling of time arguments.
|
68
152
|
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
153
|
+
# Because the UTC offset of a `Time` object in Ruby is not
|
154
|
+
# equivalent to a single timezone, the `time` argument in this
|
155
|
+
# method is first converted to a UTC equivalent before being
|
156
|
+
# used as a local time.
|
157
|
+
#
|
158
|
+
# This prevents confusion between historical UTC offsets and the UTC
|
159
|
+
# offset that the `Time` object provides. For instance, if I pass
|
160
|
+
# a "local" time with offset `+8` but the timezone actually had
|
161
|
+
# an offset of `+9` at the given historical time, there is an
|
162
|
+
# inconsistency that must be resolved.
|
163
|
+
#
|
164
|
+
# Did the user make a mistake; or is the offset intentional?
|
165
|
+
#
|
166
|
+
# One approach to solving this problem would be to raise an error,
|
167
|
+
# but this means that the user then needs to calculate the
|
168
|
+
# appropriate local offset and append that to a UTC time to satisfy
|
169
|
+
# the function. This is impractical because the offset can already
|
170
|
+
# be calculated by this library. The user should only need to
|
171
|
+
# provide a time without an offset!
|
172
|
+
#
|
173
|
+
# To resolve this inconsistency, the solution I chose was to scrub
|
174
|
+
# the offset. In the case where an offset is provided, the time is
|
175
|
+
# just converted to the UTC equivalent (without an offset). The
|
176
|
+
# resulting time is used as the local reference time.
|
177
|
+
#
|
178
|
+
# For example, if the time `08:00 +2` is passed to this function,
|
179
|
+
# the local time is assumed to be `06:00`.
|
73
180
|
def local_to_utc(time)
|
74
181
|
time = sanitize(time)
|
75
182
|
|
76
183
|
time.utc - rule_for_local(time).rules.first[OFFSET_BIT]
|
77
184
|
end
|
78
185
|
|
79
|
-
#
|
80
|
-
#
|
81
|
-
# timezone.time_with_offset(reference)
|
186
|
+
# Converts the given time to the local timezone and includes the UTC
|
187
|
+
# offset in the result.
|
82
188
|
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
|
86
|
-
|
87
|
-
# offset has been found, that offset is added to the reference UTC time
|
88
|
-
# to calculate the reference time in the timezone. The offset is then
|
89
|
-
# appended to put the time object into the proper offset.
|
90
|
-
def time_with_offset(reference)
|
91
|
-
reference = sanitize(reference)
|
189
|
+
# @param time [#to_time] the source time
|
190
|
+
# @return [Time] the time in the local timezone with the UTC offset
|
191
|
+
def time_with_offset(time)
|
192
|
+
time = sanitize(time)
|
92
193
|
|
93
|
-
utc = time
|
94
|
-
offset = utc_offset(
|
194
|
+
utc = utc_to_local(time)
|
195
|
+
offset = utc_offset(time)
|
95
196
|
Time.new(utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec, offset)
|
96
197
|
end
|
97
198
|
|
98
|
-
#
|
99
|
-
|
100
|
-
|
199
|
+
# If, at the given time, the timezone was observing Daylight Savings.
|
200
|
+
#
|
201
|
+
# @param time [#to_time] the source time
|
202
|
+
# @return [Boolean] whether the timezone, at the given time, was
|
203
|
+
# observing Daylight Savings Time
|
204
|
+
def dst?(time)
|
205
|
+
time = sanitize(time)
|
101
206
|
|
102
|
-
rule_for_utc(
|
207
|
+
rule_for_utc(time)[DST_BIT]
|
103
208
|
end
|
104
209
|
|
105
|
-
#
|
210
|
+
# Return the UTC offset (in seconds) for the given time.
|
106
211
|
#
|
107
|
-
#
|
108
|
-
|
109
|
-
|
212
|
+
# @param time [#to_time] (Time.now) the source time
|
213
|
+
# @return [Integer] the UTC offset (in seconds) in the local timezone
|
214
|
+
def utc_offset(time = nil)
|
215
|
+
time ||= Time.now
|
216
|
+
time = sanitize(time)
|
110
217
|
|
111
|
-
rule_for_utc(
|
218
|
+
rule_for_utc(time)[OFFSET_BIT]
|
112
219
|
end
|
113
220
|
|
114
|
-
|
115
|
-
|
221
|
+
# Compare one timezone with another based on current UTC offset.
|
222
|
+
#
|
223
|
+
# @param other [Timezone::Zone] the other timezone
|
224
|
+
#
|
225
|
+
# @return [-1, 0, 1, nil] comparison based on current `utc_offset`.
|
226
|
+
def <=>(other)
|
227
|
+
return nil unless other.respond_to?(:utc_offset)
|
228
|
+
|
229
|
+
utc_offset <=> other.utc_offset
|
116
230
|
end
|
117
231
|
|
118
232
|
class << self
|
119
|
-
#
|
233
|
+
# @deprecated This method will be replaced with `Timezone.names`
|
234
|
+
# in future versions of this gem.
|
120
235
|
def names
|
121
|
-
|
236
|
+
Deprecate.call(
|
237
|
+
self,
|
238
|
+
:names,
|
239
|
+
'[DEPRECATED] `::Timezone::Zone.names` will be removed in ' \
|
240
|
+
'the next gem release. Use `::Timezone.names` instead.'.freeze
|
241
|
+
)
|
242
|
+
|
243
|
+
Loader.names
|
122
244
|
end
|
123
245
|
|
124
|
-
#
|
125
|
-
#
|
126
|
-
# zones = Timezone::Zone.list(*zones)
|
127
|
-
#
|
128
|
-
# zones - An array of timezone names. (i.e. Timezone::Zones.list("America/Chicago", "Australia/Sydney"))
|
129
|
-
#
|
130
|
-
# The result is a Hash of timezones with their title, offset in seconds, UTC offset, and if it uses DST.
|
131
|
-
#
|
246
|
+
# @deprecated This functionality will be removed in the next release.
|
132
247
|
def list(*args)
|
248
|
+
Deprecate.call(
|
249
|
+
self,
|
250
|
+
:list,
|
251
|
+
'[DEPRECATED] `Zone::list` will be deprecated in the ' \
|
252
|
+
'next release of the `timezone` gem. There will be no ' \
|
253
|
+
'replacement.'.freeze
|
254
|
+
)
|
255
|
+
|
133
256
|
args = nil if args.empty? # set to nil if no args are provided
|
134
|
-
zones = args || Configure.default_for_list ||
|
135
|
-
list =
|
257
|
+
zones = args || Configure.default_for_list || names
|
258
|
+
list = names.select { |name| zones.include? name }
|
136
259
|
|
137
260
|
@zones = []
|
138
261
|
now = Time.now
|
139
|
-
list.each do |
|
140
|
-
item =
|
262
|
+
list.each do |name|
|
263
|
+
item = new(name)
|
141
264
|
@zones << {
|
142
|
-
:
|
143
|
-
:
|
144
|
-
:
|
145
|
-
:
|
146
|
-
:
|
265
|
+
zone: item.name,
|
266
|
+
title: Configure.replacements[item.name] || item.name,
|
267
|
+
offset: item.utc_offset,
|
268
|
+
utc_offset: (item.utc_offset / (60 * 60)),
|
269
|
+
dst: item.dst?(now)
|
147
270
|
}
|
148
271
|
end
|
149
272
|
@zones.sort_by! { |zone| zone[Configure.order_list_by] }
|
@@ -152,8 +275,12 @@ module Timezone
|
|
152
275
|
|
153
276
|
private
|
154
277
|
|
155
|
-
def
|
156
|
-
|
278
|
+
def private_rules
|
279
|
+
@rules ||= Loader.load(name)
|
280
|
+
end
|
281
|
+
|
282
|
+
def sanitize(time)
|
283
|
+
time.to_time
|
157
284
|
end
|
158
285
|
|
159
286
|
# Does the given time (in seconds) match this rule?
|
@@ -165,6 +292,7 @@ module Timezone
|
|
165
292
|
end
|
166
293
|
|
167
294
|
RuleSet = Struct.new(:type, :rules)
|
295
|
+
private_constant :RuleSet
|
168
296
|
|
169
297
|
def rule_for_local(local)
|
170
298
|
local = local.utc if local.respond_to?(:utc)
|
@@ -172,17 +300,17 @@ module Timezone
|
|
172
300
|
|
173
301
|
# For each rule, convert the local time into the UTC equivalent for
|
174
302
|
# that rule offset, and then check if the UTC time matches the rule.
|
175
|
-
index = binary_search(local){ |t,r| match?(t-r[OFFSET_BIT], r) }
|
176
|
-
match =
|
303
|
+
index = binary_search(local) { |t, r| match?(t - r[OFFSET_BIT], r) }
|
304
|
+
match = private_rules[index]
|
177
305
|
|
178
|
-
utc = local-match[OFFSET_BIT]
|
306
|
+
utc = local - match[OFFSET_BIT]
|
179
307
|
|
180
308
|
# If the UTC rule for the calculated UTC time does not map back to the
|
181
309
|
# same rule, then we have a skip in time and there is no applicable rule.
|
182
310
|
return RuleSet.new(:missing, [match]) if rule_for_utc(utc) != match
|
183
311
|
|
184
312
|
# If the match is the last rule, then return it.
|
185
|
-
return RuleSet.new(:single, [match]) if index ==
|
313
|
+
return RuleSet.new(:single, [match]) if index == private_rules.length - 1
|
186
314
|
|
187
315
|
# If the UTC equivalent time falls within the last hour(s) of the time
|
188
316
|
# change which were replayed during a fall-back in time, then return
|
@@ -200,43 +328,46 @@ module Timezone
|
|
200
328
|
#
|
201
329
|
# Since both rules provide valid mappings for the local time,
|
202
330
|
# we need to return both values.
|
203
|
-
|
204
|
-
|
331
|
+
last_hour =
|
332
|
+
match[SOURCE_BIT] -
|
333
|
+
match[OFFSET_BIT] +
|
334
|
+
private_rules[index + 1][OFFSET_BIT]
|
335
|
+
|
336
|
+
if utc > last_hour
|
337
|
+
RuleSet.new(:double, private_rules[index..(index + 1)])
|
205
338
|
else
|
206
339
|
RuleSet.new(:single, [match])
|
207
340
|
end
|
208
341
|
end
|
209
342
|
|
210
|
-
def rule_for_utc(time)
|
343
|
+
def rule_for_utc(time)
|
211
344
|
time = time.utc if time.respond_to?(:utc)
|
212
345
|
time = time.to_i
|
213
346
|
|
214
|
-
|
347
|
+
private_rules[binary_search(time) { |t, r| match?(t, r) }]
|
215
348
|
end
|
216
349
|
|
217
350
|
# Find the first rule that matches using binary search.
|
218
|
-
def binary_search(time, from=0, to=nil, &block)
|
219
|
-
to =
|
351
|
+
def binary_search(time, from = 0, to = nil, &block)
|
352
|
+
to = private_rules.length - 1 if to.nil?
|
220
353
|
|
221
354
|
return from if from == to
|
222
355
|
|
223
356
|
mid = (from + to) / 2
|
224
357
|
|
225
|
-
if
|
358
|
+
if yield(time, private_rules[mid])
|
226
359
|
return mid if mid == 0
|
227
360
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
return binary_search(time, from, mid-1, &block)
|
232
|
-
end
|
361
|
+
return mid unless yield(time, private_rules[mid - 1])
|
362
|
+
|
363
|
+
binary_search(time, from, mid - 1, &block)
|
233
364
|
else
|
234
365
|
return binary_search(time, mid + 1, to, &block)
|
235
366
|
end
|
236
367
|
end
|
237
368
|
|
238
|
-
def timezone_id(lat, lon)
|
239
|
-
Timezone::Configure.lookup.lookup(lat,lon)
|
369
|
+
def timezone_id(lat, lon)
|
370
|
+
Timezone::Configure.lookup.lookup(lat, lon)
|
240
371
|
end
|
241
372
|
end
|
242
373
|
end
|
data/lib/timezone.rb
CHANGED
@@ -1,3 +1,77 @@
|
|
1
1
|
require 'timezone/zone'
|
2
|
+
require 'timezone/nil_zone'
|
3
|
+
require 'timezone/lookup'
|
4
|
+
require 'timezone/loader'
|
2
5
|
|
3
|
-
|
6
|
+
# Main entry point for all timezone related functionality.
|
7
|
+
module Timezone
|
8
|
+
# A list of all timezone names.
|
9
|
+
#
|
10
|
+
# @return [Array<String>] all the timezone names
|
11
|
+
def self.names
|
12
|
+
Loader.names
|
13
|
+
end
|
14
|
+
|
15
|
+
# Retrieve a timezone by name.
|
16
|
+
#
|
17
|
+
# @param name [String] the timezone name
|
18
|
+
#
|
19
|
+
# @return [Timezone::Zone] if the timezone is found
|
20
|
+
# @return [Timezone::NilZone] if the timezone is not found
|
21
|
+
def self.[](name)
|
22
|
+
fetch(name) { ::Timezone::NilZone.new }
|
23
|
+
end
|
24
|
+
|
25
|
+
# Fetch a timezone by name.
|
26
|
+
#
|
27
|
+
# @param name [String] the timezone name
|
28
|
+
# @param default an object to return if timezone is
|
29
|
+
# not found
|
30
|
+
# @yield the block to run if the timezone is not found
|
31
|
+
# @yieldparam name [String] the timezone name if the timezone is not
|
32
|
+
# found
|
33
|
+
#
|
34
|
+
# @return [Timezone::Zone] if the timezone is found
|
35
|
+
# @return [Object] if the timezone is not found and a default
|
36
|
+
# value or block has been provided
|
37
|
+
#
|
38
|
+
# @raise [Timezone::Error::InvalidZone] if the timezone is not found
|
39
|
+
# and a default value and block have not been provided
|
40
|
+
def self.fetch(name, default = :__block, &block)
|
41
|
+
return ::Timezone::Zone.new(name) if Loader.valid?(name)
|
42
|
+
|
43
|
+
if block_given? && default != :__block
|
44
|
+
warn('warning: block supersedes default value argument'.freeze)
|
45
|
+
end
|
46
|
+
|
47
|
+
return block.call(name) if block_given?
|
48
|
+
return default unless default == :__block
|
49
|
+
|
50
|
+
raise ::Timezone::Error::InvalidZone
|
51
|
+
end
|
52
|
+
|
53
|
+
# Lookup a timezone name by (lat, long) and then fetch the
|
54
|
+
# timezone object.
|
55
|
+
#
|
56
|
+
# @param lat [Double] the latitude coordinate
|
57
|
+
# @param long [Double] the longitude coordinate
|
58
|
+
# @param default an optional object to return if the remote lookup
|
59
|
+
# succeeds but the timezone is not found
|
60
|
+
# @yield the block to run if the remote lookup succeeds and the
|
61
|
+
# timezone is not found
|
62
|
+
# @yieldparam name [String] the timezone name if the remote lookup
|
63
|
+
# succeeds and the timezone is not found
|
64
|
+
#
|
65
|
+
# @return [Timezone::Zone] if the remote lookup succeeds and the
|
66
|
+
# timezone is found
|
67
|
+
# @return [Object] if the remote lookup succeeds, the timezone is
|
68
|
+
# not found, and a default value or block has been provided
|
69
|
+
#
|
70
|
+
# @raise [Timezone::Error::InvalidZone] if the remote lookup
|
71
|
+
# succeeds but the resulting timezone is not found and a default
|
72
|
+
# value or block has not been provided
|
73
|
+
# @raise [Timezone::Error::Lookup] if the remote lookup fails
|
74
|
+
def self.lookup(lat, long, default = :__block, &block)
|
75
|
+
fetch(::Timezone::Lookup.lookup.lookup(lat, long), default, &block)
|
76
|
+
end
|
77
|
+
end
|
data/test/basic_lookup_test.rb
CHANGED
@@ -12,12 +12,12 @@ class BasicLookupTest < ::Minitest::Unit::TestCase
|
|
12
12
|
|
13
13
|
def test_missing_protocol
|
14
14
|
config.protocol = nil
|
15
|
-
assert_raises(::Timezone::Error::InvalidConfig){ lookup }
|
15
|
+
assert_raises(::Timezone::Error::InvalidConfig) { lookup }
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_missing_url
|
19
19
|
config.url = nil
|
20
|
-
assert_raises(::Timezone::Error::InvalidConfig){ lookup }
|
20
|
+
assert_raises(::Timezone::Error::InvalidConfig) { lookup }
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_initialization
|
@@ -17,24 +17,31 @@ class GeonamesLookupTest < ::Minitest::Unit::TestCase
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def lookup
|
20
|
-
::Timezone::
|
20
|
+
::Timezone::Configure.lookup
|
21
|
+
end
|
22
|
+
|
23
|
+
def clear
|
24
|
+
Timezone::Configure.instance_variable_set(:@lookup, nil)
|
25
|
+
Timezone::Configure.instance_variable_set(:@google_lookup, nil)
|
26
|
+
Timezone::Configure.instance_variable_set(:@geonames_lookup, nil)
|
21
27
|
end
|
22
28
|
|
23
29
|
def test_missing_username
|
24
|
-
|
25
|
-
|
30
|
+
clear
|
31
|
+
Timezone::Configure.begin { |c| c.username = nil }
|
32
|
+
assert_raises(::Timezone::Error::InvalidConfig) { lookup }
|
26
33
|
ensure
|
27
|
-
Timezone::Configure.begin{ |c| c.username = 'timezone' }
|
34
|
+
Timezone::Configure.begin { |c| c.username = 'timezone' }
|
28
35
|
end
|
29
36
|
|
30
37
|
def test_lookup
|
31
|
-
|
38
|
+
lookup.client.body = File.open(mock_path + '/lat_lon_coords.txt').read
|
32
39
|
|
33
40
|
assert_equal 'Australia/Adelaide', lookup.lookup(*coordinates)
|
34
41
|
end
|
35
42
|
|
36
43
|
def test_api_limit
|
37
|
-
|
44
|
+
lookup.client.body = File.open(mock_path + '/api_limit_reached.txt').read
|
38
45
|
|
39
46
|
assert_raises Timezone::Error::GeoNames, 'api limit reached' do
|
40
47
|
lookup.lookup(*coordinates)
|