timezone 0.6.0 → 0.99.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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)
|