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 CHANGED
@@ -1,3 +1,7 @@
1
+ # 0.3.4
2
+
3
+ * Added support for Google Timezone API. (amnesia7)
4
+
1
5
  # 0.3.3
2
6
 
3
7
  * Updated parsing code. (panthomakos)
@@ -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 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](http://www.geonames.org/export/web-services.html) for timezone latitude and longitude lookup.
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
- Finally, pass the coordinates to your timezone initialization function.
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
- API calls to Geonames, you can write your own very simple http client wrapper
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)
@@ -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.url = 'api.geonames.org'
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 [Sting]
51
+ # @return [String]
24
52
  # the Geonames API URL ('api.geonames.org')
25
- def self.url
26
- @@url ||= 'api.geonames.org'
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 [Sting] url
59
+ # @param [String] url
32
60
  # the Geonames API URL
33
- def self.url=(url)
34
- @@url = url
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.protocol=(protocol)
42
- @@protocol = protocol
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 [Sting]
48
- # the Geonames API URL ('api.geonames.org')
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
- @protocol ||= 'http'
130
+ use_google? ? google_protocol : geonames_protocol
51
131
  end
52
132
 
53
- # The HTTP client that handles requests to geonames
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 geonames
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 geonames
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
- def self.username= username
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
 
@@ -11,6 +11,7 @@ module Timezone
11
11
  class InvalidZone < Base; end
12
12
  class NilZone < Base; end
13
13
  class GeoNames < Base; end
14
+ class Google < Base; end
14
15
  class ParseTime < Base; end
15
16
  end
16
- end
17
+ end
@@ -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 can create
6
- # your own version of this class if you want to use a proxy or a
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)
@@ -1,3 +1,3 @@
1
1
  module Timezone
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.4"
3
3
  end
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
- response = http_client.get("/timezoneJSON?lat=#{lat}&lng=#{lon}&username=#{Timezone::Configure.username}")
152
- return nil unless response.code =~ /^2\d\d$/
151
+ if Timezone::Configure.use_google?
152
+ timestamp = Time.now.to_i
153
+ lookupUrl = "/maps/api/timezone/json?location=#{lat},#{lon}&timestamp=#{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
- data = JSON.parse(response.body)
160
+ response = http_client.get(lookupUrl)
155
161
 
156
- if data['status'] && data['status']['value'] == 18
157
- raise Timezone::Error::GeoNames, "api limit reached"
158
- end
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
- return data['timezoneId']
176
+ return data[timezoneId]
177
+ end
161
178
  rescue => e
162
- raise Timezone::Error::GeoNames, e.message
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
 
@@ -0,0 +1,8 @@
1
+ {
2
+ "dstOffset" : 3600,
3
+ "rawOffset" : 34200,
4
+ "status" : "OK",
5
+ "timeZoneId" : "Australia/Adelaide",
6
+ "timeZoneName" : "Australian Central Daylight Time"
7
+ }
8
+
@@ -0,0 +1,5 @@
1
+ {
2
+ "errorMessage" : "The provided API key is invalid.",
3
+ "status" : "REQUEST_DENIED"
4
+ }
5
+
@@ -162,7 +162,7 @@ class TimezoneTest < Test::Unit::TestCase
162
162
  end
163
163
  end
164
164
 
165
- def test_using_lat_lon_coordinates
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.url = 'www.newtimezoneserver.com' }
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.url = nil }
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 for timezone latitude and longitude lookup (http://www.geonames.org/export/web-services.html).}
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.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-11-23 00:00:00.000000000 Z
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 for timezone latitude and longitude lookup (http://www.geonames.org/export/web-services.html).
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.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: