timezone 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.markdown +4 -0
- data/CONTRIBUTING.markdown +5 -0
- data/README.markdown +22 -7
- data/lib/timezone/configure.rb +104 -16
- data/lib/timezone/error.rb +2 -1
- data/lib/timezone/net_http_client.rb +5 -3
- data/lib/timezone/version.rb +1 -1
- data/lib/timezone/zone.rb +29 -8
- data/test/mocks/google_lat_lon_coords.txt +8 -0
- data/test/mocks/google_request_denied.txt +5 -0
- data/test/timezone_test.rb +30 -3
- data/timezone.gemspec +1 -1
- metadata +10 -4
data/CHANGES.markdown
CHANGED
data/CONTRIBUTING.markdown
CHANGED
@@ -10,3 +10,8 @@
|
|
10
10
|
* Extract and use `zic` to load data into `/usr/share/zoneinfo`.
|
11
11
|
* Run `bundle exec rake parse` to parse files in `right/` directory into
|
12
12
|
the local `data` directory.
|
13
|
+
|
14
|
+
# Notes
|
15
|
+
|
16
|
+
* How to read TZData IANA source files:
|
17
|
+
http://www.cstdbill.com/tzdb/tz-how-to.html
|
data/README.markdown
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# Timezone
|
2
2
|
|
3
|
-
A simple way to get accurate current and historical timezone information based
|
3
|
+
A simple way to get accurate current and historical timezone information based
|
4
|
+
on zone or latitude and longitude coordinates. This gem uses the
|
5
|
+
[tz database][tz-database] for historical timezone information. It also uses the
|
6
|
+
[geonames API][geonames-api] or the [Google Timezone API][google-api] for
|
7
|
+
timezone latitude and longitude lookup.
|
8
|
+
|
9
|
+
[tz-database]: http://www.twinsun.com/tz/tz-link.htm
|
10
|
+
[geonames-api]: http://www.geonames.org/export/web-services.html
|
11
|
+
[google-api]: https://developers.google.com/maps/documentation/timezone/
|
4
12
|
|
5
13
|
## Installation
|
6
14
|
|
@@ -47,7 +55,15 @@ Second, add the following to your application.rb file, or before you perform a c
|
|
47
55
|
c.username = 'your_geonames_username_goes_here'
|
48
56
|
end
|
49
57
|
|
50
|
-
|
58
|
+
Alternatively, timezone can be used with a Google api key, which you can get [here](https://code.google.com/apis/console/).
|
59
|
+
|
60
|
+
Next, add the following to your application.rb file, or before you perform a coordinate lookup.
|
61
|
+
|
62
|
+
Timezone::Configure.begin do |c|
|
63
|
+
c.google_api_key = 'your_google_api_key_goes_here'
|
64
|
+
end
|
65
|
+
|
66
|
+
Finally, for either geonames or Google implementation, pass the coordinates to your timezone initialization function.
|
51
67
|
|
52
68
|
timezone = Timezone::Zone.new :latlon => [-34.92771808058, 138.477041423321]
|
53
69
|
timezone.zone
|
@@ -74,7 +90,7 @@ If you need information from a specific set of timezones rather than a complete
|
|
74
90
|
|
75
91
|
zone_list = Timezone::Zone.list "America/Chicago", "America/New_York", "America/Boise"
|
76
92
|
# This will return an array of information hashes in the following format:
|
77
|
-
# {
|
93
|
+
# {
|
78
94
|
# :zone => "America/Chicago",
|
79
95
|
# :title => "America/Chicago", # this can be customized to your needs
|
80
96
|
# :offset => -18000, # UTC offset in seconds
|
@@ -98,14 +114,13 @@ Finally, by default the **Zone#list** method will order the results by the timez
|
|
98
114
|
|
99
115
|
Timezone::Configure.begin do |c|
|
100
116
|
# this can equal any hash key returned by the Zone#list method
|
101
|
-
c.order_list_by = :title
|
117
|
+
c.order_list_by = :title
|
102
118
|
end
|
103
119
|
|
104
120
|
## Using Your Own HTTP Client
|
105
121
|
|
106
|
-
If you have non-standard http request needs or want to have more control over
|
107
|
-
|
108
|
-
instead of using the built-in default.
|
122
|
+
If you have non-standard http request needs or want to have more control over API calls to Geonames and Google, you can write your own very simple http client wrapper instead of using the built-in default.
|
123
|
+
Be aware that the Google timezone API uses `https` protocol.
|
109
124
|
|
110
125
|
class MyHTTPClient
|
111
126
|
def initialize(protocol, host)
|
data/lib/timezone/configure.rb
CHANGED
@@ -7,50 +7,130 @@ module Timezone
|
|
7
7
|
# {http://www.geonames.org/login Geonames}. Use the username to
|
8
8
|
# configure your application for latitude and longitude based
|
9
9
|
# timezone searches.
|
10
|
+
# Alternatively, you'll want to sign up for a Google api key at
|
11
|
+
# {https://code.google.com/apis/console/ Google}. Use the api key to
|
12
|
+
# configure your application for latitude and longitude based
|
13
|
+
# timezone searches.
|
10
14
|
#
|
11
15
|
# If you aren't going to initialize timezone objects based on lat,lng
|
12
16
|
# then this configuration is not necessary.
|
13
17
|
#
|
14
18
|
# @example
|
15
19
|
# Timezone::Configure.begin do |c|
|
16
|
-
# c.
|
20
|
+
# c.geonames_url = 'api.geonames.org'
|
17
21
|
# c.username = 'foo-bar'
|
22
|
+
# c.google_api_key = 'abc123'
|
18
23
|
# end
|
19
24
|
#
|
20
25
|
class Configure
|
26
|
+
# The Google API key
|
27
|
+
#
|
28
|
+
# @return [String]
|
29
|
+
# the Google API key ('abc123')
|
30
|
+
def self.google_api_key
|
31
|
+
@google_api_key
|
32
|
+
end
|
33
|
+
|
34
|
+
# Google API key
|
35
|
+
#
|
36
|
+
# @param [String] api_key
|
37
|
+
# the Google API key
|
38
|
+
def self.google_api_key=(api_key)
|
39
|
+
@google_api_key = api_key
|
40
|
+
end
|
41
|
+
|
42
|
+
# Use Google API if key has been set
|
43
|
+
#
|
44
|
+
# @return [Boolean]
|
45
|
+
def self.use_google?
|
46
|
+
!!google_api_key
|
47
|
+
end
|
48
|
+
|
21
49
|
# The Geonames API URL
|
22
50
|
#
|
23
|
-
# @return [
|
51
|
+
# @return [String]
|
24
52
|
# the Geonames API URL ('api.geonames.org')
|
25
|
-
def self.
|
26
|
-
@@
|
53
|
+
def self.geonames_url
|
54
|
+
@@geonames_url ||= 'api.geonames.org'
|
27
55
|
end
|
28
56
|
|
29
57
|
# The Geonames API URL
|
30
58
|
#
|
31
|
-
# @param [
|
59
|
+
# @param [String] url
|
32
60
|
# the Geonames API URL
|
33
|
-
def self.
|
34
|
-
@@
|
61
|
+
def self.geonames_url=(url)
|
62
|
+
@@geonames_url = url
|
63
|
+
end
|
64
|
+
|
65
|
+
class << self
|
66
|
+
alias :url= :geonames_url=
|
67
|
+
end
|
68
|
+
|
69
|
+
# The Google API URL
|
70
|
+
#
|
71
|
+
# @return [String]
|
72
|
+
# the Google API URL ('maps.googleapis.com')
|
73
|
+
def self.google_url
|
74
|
+
@@google_url ||= 'maps.googleapis.com'
|
75
|
+
end
|
76
|
+
|
77
|
+
# The Google API URL
|
78
|
+
#
|
79
|
+
# @param [String] url
|
80
|
+
# the Google API URL
|
81
|
+
def self.google_url=(url)
|
82
|
+
@@google_url = url
|
83
|
+
end
|
84
|
+
|
85
|
+
# Use Google URL if key has been set else use Geonames URL
|
86
|
+
#
|
87
|
+
# @return [String]
|
88
|
+
# the Google or Geonames API URL
|
89
|
+
def self.url
|
90
|
+
use_google? ? google_url : geonames_url
|
35
91
|
end
|
36
92
|
|
37
93
|
# The Geonames API HTTP protocol
|
38
94
|
#
|
39
95
|
# @param [String] protocol
|
40
96
|
# the Geonames API HTTP procotol
|
41
|
-
def self.
|
42
|
-
@@
|
97
|
+
def self.geonames_protocol=(protocol)
|
98
|
+
@@geonames_protocol = protocol
|
43
99
|
end
|
44
100
|
|
45
101
|
# The Geonames API HTTP protocol
|
46
102
|
#
|
47
|
-
# @return [
|
48
|
-
# the Geonames API
|
103
|
+
# @return [String]
|
104
|
+
# the Geonames API HTTP protocol ('http')
|
105
|
+
def self.geonames_protocol
|
106
|
+
@@geonames_protocol ||= 'http'
|
107
|
+
end
|
108
|
+
|
109
|
+
# The Google API HTTP protocol
|
110
|
+
#
|
111
|
+
# @param [String] protocol
|
112
|
+
# the Google API HTTP procotol
|
113
|
+
def self.google_protocol=(protocol)
|
114
|
+
@@google_protocol = protocol
|
115
|
+
end
|
116
|
+
|
117
|
+
# The Google API HTTP protocol
|
118
|
+
#
|
119
|
+
# @return [String]
|
120
|
+
# the Google API HTTP protocol ('https')
|
121
|
+
def self.google_protocol
|
122
|
+
@@google_protocol ||= 'https'
|
123
|
+
end
|
124
|
+
|
125
|
+
# Use Google protocol if key has been set else use Geonames protocol
|
126
|
+
#
|
127
|
+
# @return [String]
|
128
|
+
# the Google or Geonames API protocol
|
49
129
|
def self.protocol
|
50
|
-
|
130
|
+
use_google? ? google_protocol : geonames_protocol
|
51
131
|
end
|
52
132
|
|
53
|
-
# The HTTP client that handles requests to
|
133
|
+
# The HTTP client that handles requests to Geonames and Google
|
54
134
|
#
|
55
135
|
# @return [Object]
|
56
136
|
# the HTTP client ({Timezone::NetHTTPClient Timezone::NetHTTPClient})
|
@@ -58,20 +138,28 @@ module Timezone
|
|
58
138
|
@@http_client ||= Timezone::NetHTTPClient
|
59
139
|
end
|
60
140
|
|
61
|
-
# The HTTP client that handles requests to
|
141
|
+
# The HTTP client that handles requests to Geonames and Google
|
62
142
|
#
|
63
143
|
# @param [Object] client
|
64
|
-
# the HTTP client that handles requests to
|
144
|
+
# the HTTP client that handles requests to Geonames and Google
|
65
145
|
#
|
66
146
|
def self.http_client=(client)
|
67
147
|
@@http_client = client
|
68
148
|
end
|
69
149
|
|
150
|
+
# The Geonames API username
|
151
|
+
#
|
152
|
+
# @return [String]
|
153
|
+
# the Geonames API username ('foo-bar')
|
70
154
|
def self.username
|
71
155
|
@@username
|
72
156
|
end
|
73
157
|
|
74
|
-
|
158
|
+
# The Geonames API username
|
159
|
+
#
|
160
|
+
# @param [String] username
|
161
|
+
# the Geonames API username
|
162
|
+
def self.username=(username)
|
75
163
|
@@username = username
|
76
164
|
end
|
77
165
|
|
data/lib/timezone/error.rb
CHANGED
@@ -2,9 +2,10 @@ require 'uri'
|
|
2
2
|
require 'net/http'
|
3
3
|
|
4
4
|
module Timezone
|
5
|
-
# A basic HTTP Client that handles requests to Geonames. You
|
6
|
-
# your own version of this class if you want to use a proxy
|
7
|
-
# different http library such as faraday
|
5
|
+
# A basic HTTP Client that handles requests to Geonames and Google. You
|
6
|
+
# can create your own version of this class if you want to use a proxy
|
7
|
+
# or a different http library such as faraday but be aware that the
|
8
|
+
# Google timezone API uses https protocol.
|
8
9
|
#
|
9
10
|
# @example
|
10
11
|
# Timezone::Configure.begin do |c|
|
@@ -14,6 +15,7 @@ module Timezone
|
|
14
15
|
def initialize(protocol, host)
|
15
16
|
uri = URI.parse("#{protocol}://#{host}")
|
16
17
|
@http = Net::HTTP.new(uri.host, uri.port)
|
18
|
+
@http.use_ssl = (protocol == 'https')
|
17
19
|
end
|
18
20
|
|
19
21
|
def get(url)
|
data/lib/timezone/version.rb
CHANGED
data/lib/timezone/zone.rb
CHANGED
@@ -148,18 +148,39 @@ module Timezone
|
|
148
148
|
|
149
149
|
def timezone_id lat, lon #:nodoc:
|
150
150
|
begin
|
151
|
-
|
152
|
-
|
151
|
+
if Timezone::Configure.use_google?
|
152
|
+
timestamp = Time.now.to_i
|
153
|
+
lookupUrl = "/maps/api/timezone/json?location=#{lat},#{lon}×tamp=#{timestamp}&key=#{Timezone::Configure.google_api_key}"
|
154
|
+
timezoneId = 'timeZoneId' # uppercase 'Z'
|
155
|
+
else
|
156
|
+
lookupUrl = "/timezoneJSON?lat=#{lat}&lng=#{lon}&username=#{Timezone::Configure.username}"
|
157
|
+
timezoneId = 'timezoneId' # lowercase 'z'
|
158
|
+
end
|
153
159
|
|
154
|
-
|
160
|
+
response = http_client.get(lookupUrl)
|
155
161
|
|
156
|
-
if
|
157
|
-
|
158
|
-
|
162
|
+
if response.code =~ /^2\d\d$/
|
163
|
+
data = JSON.parse(response.body)
|
164
|
+
|
165
|
+
# check response
|
166
|
+
if Timezone::Configure.use_google?
|
167
|
+
if data['status'] != 'OK'
|
168
|
+
raise Timezone::Error::Google, data['errorMessage']
|
169
|
+
end
|
170
|
+
else
|
171
|
+
if data['status'] && data['status']['value'] == 18
|
172
|
+
raise Timezone::Error::GeoNames, 'api limit reached'
|
173
|
+
end
|
174
|
+
end
|
159
175
|
|
160
|
-
|
176
|
+
return data[timezoneId]
|
177
|
+
end
|
161
178
|
rescue => e
|
162
|
-
|
179
|
+
if Timezone::Configure.use_google?
|
180
|
+
raise Timezone::Error::Google, e.message
|
181
|
+
else
|
182
|
+
raise Timezone::Error::GeoNames, e.message
|
183
|
+
end
|
163
184
|
end
|
164
185
|
end
|
165
186
|
|
data/test/timezone_test.rb
CHANGED
@@ -162,7 +162,7 @@ class TimezoneTest < Test::Unit::TestCase
|
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
165
|
-
def
|
165
|
+
def test_geonames_using_lat_lon_coordinates
|
166
166
|
mock_path = File.expand_path(File.join(File.dirname(__FILE__), 'mocks'))
|
167
167
|
HTTPTestClient.body = File.open(mock_path + '/lat_lon_coords.txt').read
|
168
168
|
|
@@ -189,6 +189,33 @@ class TimezoneTest < Test::Unit::TestCase
|
|
189
189
|
end
|
190
190
|
end
|
191
191
|
|
192
|
+
def test_google_using_lat_lon_coordinates
|
193
|
+
mock_path = File.expand_path(File.join(File.dirname(__FILE__), 'mocks'))
|
194
|
+
HTTPTestClient.body = File.open(mock_path + '/google_lat_lon_coords.txt').read
|
195
|
+
|
196
|
+
Timezone::Configure.begin do |c|
|
197
|
+
c.http_client = HTTPTestClient
|
198
|
+
c.google_api_key = '123abc'
|
199
|
+
end
|
200
|
+
|
201
|
+
timezone = Timezone::Zone.new :latlon => [-34.92771808058, 138.477041423321]
|
202
|
+
assert_equal 'Australia/Adelaide', timezone.zone
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_google_request_denied_read_lat_lon_coordinates
|
206
|
+
mock_path = File.expand_path(File.join(File.dirname(__FILE__), 'mocks'))
|
207
|
+
HTTPTestClient.body = File.open(mock_path + '/google_request_denied.txt').read
|
208
|
+
|
209
|
+
Timezone::Configure.begin do |c|
|
210
|
+
c.http_client = HTTPTestClient
|
211
|
+
c.google_api_key = 'invalid-api-key'
|
212
|
+
end
|
213
|
+
|
214
|
+
assert_raise Timezone::Error::Google, 'The provided API key is invalid.' do
|
215
|
+
Timezone::Zone.new :latlon => [-34.92771808058, 138.477041423321]
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
192
219
|
def test_australian_timezone_with_dst
|
193
220
|
timezone = Timezone::Zone.new :zone => 'Australia/Adelaide'
|
194
221
|
utc = Time.utc(2010, 12, 23, 19, 37, 15)
|
@@ -201,10 +228,10 @@ class TimezoneTest < Test::Unit::TestCase
|
|
201
228
|
end
|
202
229
|
|
203
230
|
def test_configure_url_custom
|
204
|
-
Timezone::Configure.begin { |c| c.
|
231
|
+
Timezone::Configure.begin { |c| c.geonames_url = 'www.newtimezoneserver.com' }
|
205
232
|
assert_equal 'www.newtimezoneserver.com', Timezone::Configure.url
|
206
233
|
# clean up url after test
|
207
|
-
Timezone::Configure.begin { |c| c.
|
234
|
+
Timezone::Configure.begin { |c| c.geonames_url = nil }
|
208
235
|
end
|
209
236
|
|
210
237
|
def test_utc_offset_without_dst
|
data/timezone.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.email = ["pan.thomakos@gmail.com"]
|
11
11
|
s.homepage = "http://github.com/panthomakos/timezone"
|
12
12
|
s.summary = "timezone-#{Timezone::VERSION}"
|
13
|
-
s.description = %q{A simple way to get accurate current and historical timezone information based on zone or latitude and longitude coordinates. This gem uses the tz database (http://www.twinsun.com/tz/tz-link.htm) for historical timezone information. It also uses the geonames API
|
13
|
+
s.description = %q{A simple way to get accurate current and historical timezone information based on zone or latitude and longitude coordinates. This gem uses the tz database (http://www.twinsun.com/tz/tz-link.htm) for historical timezone information. It also uses either the geonames API (http://www.geonames.org/export/web-services.html) or Google timezone API (https://developers.google.com/maps/documentation/timezone/) for timezone latitude and longitude lookup.}
|
14
14
|
s.license = 'MIT'
|
15
15
|
|
16
16
|
s.rubyforge_project = "timezone"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timezone
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-12-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -78,7 +78,9 @@ dependencies:
|
|
78
78
|
description: A simple way to get accurate current and historical timezone information
|
79
79
|
based on zone or latitude and longitude coordinates. This gem uses the tz database
|
80
80
|
(http://www.twinsun.com/tz/tz-link.htm) for historical timezone information. It
|
81
|
-
also uses the geonames API
|
81
|
+
also uses either the geonames API (http://www.geonames.org/export/web-services.html)
|
82
|
+
or Google timezone API (https://developers.google.com/maps/documentation/timezone/)
|
83
|
+
for timezone latitude and longitude lookup.
|
82
84
|
email:
|
83
85
|
- pan.thomakos@gmail.com
|
84
86
|
executables: []
|
@@ -689,6 +691,8 @@ files:
|
|
689
691
|
- test/data/Helsinki_rules_without_timestamps.json
|
690
692
|
- test/data/asia
|
691
693
|
- test/mocks/api_limit_reached.txt
|
694
|
+
- test/mocks/google_lat_lon_coords.txt
|
695
|
+
- test/mocks/google_request_denied.txt
|
692
696
|
- test/mocks/lat_lon_coords.txt
|
693
697
|
- test/timezone_test.rb
|
694
698
|
- timezone.gemspec
|
@@ -717,11 +721,13 @@ rubyforge_project: timezone
|
|
717
721
|
rubygems_version: 1.8.23.2
|
718
722
|
signing_key:
|
719
723
|
specification_version: 3
|
720
|
-
summary: timezone-0.3.
|
724
|
+
summary: timezone-0.3.4
|
721
725
|
test_files:
|
722
726
|
- test/data/Helsinki_rules_without_timestamps.json
|
723
727
|
- test/data/asia
|
724
728
|
- test/mocks/api_limit_reached.txt
|
729
|
+
- test/mocks/google_lat_lon_coords.txt
|
730
|
+
- test/mocks/google_request_denied.txt
|
725
731
|
- test/mocks/lat_lon_coords.txt
|
726
732
|
- test/timezone_test.rb
|
727
733
|
has_rdoc:
|