timezone 0.0.3 → 0.1.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.
- data/README.markdown +1 -1
- data/lib/timezone.rb +2 -104
- data/lib/timezone/configure.rb +24 -0
- data/lib/timezone/error.rb +16 -0
- data/lib/timezone/version.rb +1 -1
- data/lib/timezone/zone.rb +74 -0
- data/test/timezone_test.rb +11 -8
- metadata +6 -3
data/README.markdown
CHANGED
@@ -1,6 +1,6 @@
|
|
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
|
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.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
data/lib/timezone.rb
CHANGED
@@ -1,105 +1,3 @@
|
|
1
|
-
require '
|
2
|
-
require 'date'
|
3
|
-
require 'time'
|
4
|
-
require 'net/http'
|
1
|
+
require File.expand_path('../timezone/zone', __FILE__)
|
5
2
|
|
6
|
-
|
7
|
-
attr_accessor :rules, :zone
|
8
|
-
|
9
|
-
# Configuration class for the Timezone gem.
|
10
|
-
#
|
11
|
-
# Timezone::Configure.begin do |c| ... end
|
12
|
-
# c.username = username - the geonames username you use to access the geonames timezone API.
|
13
|
-
#
|
14
|
-
# Signup for a geonames username at http://www.geonames.org/login. Use that username to configure
|
15
|
-
# your application for latitude and longitude based timezone searches. If you aren't going to
|
16
|
-
# initialize timezone objects based on latitude and longitude then this configuration is not necessary.
|
17
|
-
class Configure
|
18
|
-
def self.username
|
19
|
-
@@username
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.username= username
|
23
|
-
@@username = username
|
24
|
-
end
|
25
|
-
|
26
|
-
def self.begin
|
27
|
-
yield self
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Error messages that can be raised by this gem. To catch any related error message, simply use Error::Base.
|
32
|
-
#
|
33
|
-
# begin
|
34
|
-
# ...
|
35
|
-
# rescue Timezone::Error::Base => e
|
36
|
-
# puts "Timezone Error: #{e.message}"
|
37
|
-
# end
|
38
|
-
module Error
|
39
|
-
class Base < StandardError; end
|
40
|
-
class InvalidZone < Base; end
|
41
|
-
class NilZone < Base; end
|
42
|
-
class GeoNames < Base; end
|
43
|
-
class ParseTime < Base; end
|
44
|
-
end
|
45
|
-
|
46
|
-
# Create a new Timezone object.
|
47
|
-
#
|
48
|
-
# Timezone.new(options)
|
49
|
-
# :zone - The actual name of the zone. For example, Australia/Sydney or Americas/Los_Angeles.
|
50
|
-
# :lat, :lon - The latitude and longitude of the location.
|
51
|
-
# :latlon - The array of latitude and longitude of the location.
|
52
|
-
#
|
53
|
-
# If a latitude and longitude is passed in, the Timezone object will do a lookup for the actual zone
|
54
|
-
# name and then use that as a reference. It will then load the appropriate json timezone information
|
55
|
-
# for that zone, and compile a list of the timezone rules.
|
56
|
-
def initialize options
|
57
|
-
if options.has_key?(:lat) && options.has_key?(:lon)
|
58
|
-
options[:zone] = timezone_id options[:lat], options[:lon]
|
59
|
-
elsif options.has_key?(:latlon)
|
60
|
-
options[:zone] = timezone_id *options[:latlon]
|
61
|
-
end
|
62
|
-
|
63
|
-
raise Error::NilZone, 'No zone was found. Please specify a zone.' if options[:zone].nil?
|
64
|
-
|
65
|
-
file = File.join File.expand_path(File.dirname(__FILE__)+'/../data'), "#{options[:zone]}.json"
|
66
|
-
raise Error::InvalidZone, "'#{options[:zone]}' is not a valid zone." unless File.exists?(file)
|
67
|
-
|
68
|
-
data = JSON.parse(open(file).read)
|
69
|
-
@rules = data['zone']
|
70
|
-
@zone = data['_zone'] || options[:zone]
|
71
|
-
end
|
72
|
-
|
73
|
-
# Determine the time in the timezone.
|
74
|
-
#
|
75
|
-
# timezone.time(reference)
|
76
|
-
# reference - The Time you want to convert.
|
77
|
-
#
|
78
|
-
# The reference is converted to a UTC equivalent. That UTC equivalent is then used to lookup the appropriate
|
79
|
-
# offset in the timezone rules. Once the offset has been found that offset is added to the reference UTC time
|
80
|
-
# to calculate the reference time in the timezone.
|
81
|
-
def time reference
|
82
|
-
reference = reference.utc
|
83
|
-
rule = rules.detect{ |rule| _parsetime(rule['_from']) <= reference && _parsetime(rule['_to']) >= reference }
|
84
|
-
reference + rule['offset']
|
85
|
-
end
|
86
|
-
|
87
|
-
private
|
88
|
-
|
89
|
-
def timezone_id lat, lon #:nodoc:
|
90
|
-
begin
|
91
|
-
response = Net::HTTP.get('ws.geonames.org', "/timezoneJSON?lat=#{lat}&lng=#{lon}&username=#{Configure.username}")
|
92
|
-
JSON.parse(response)['timezoneId']
|
93
|
-
rescue Exception => e
|
94
|
-
raise Error::GeoNames, e.message
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def _parsetime time #:nodoc:
|
99
|
-
begin
|
100
|
-
Time.strptime(time, "%Y-%m-%dT%H:%M:%SZ")
|
101
|
-
rescue Exception => e
|
102
|
-
raise Error::ParseTime, e.message
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
3
|
+
module Timezone; end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Timezone
|
2
|
+
# Configuration class for the Timezone gem.
|
3
|
+
#
|
4
|
+
# Timezone::Configure.begin do |c| ... end
|
5
|
+
#
|
6
|
+
# c.username = username - the geonames username you use to access the geonames timezone API.
|
7
|
+
#
|
8
|
+
# Signup for a geonames username at http://www.geonames.org/login. Use that username to configure
|
9
|
+
# your application for latitude and longitude based timezone searches. If you aren't going to
|
10
|
+
# initialize timezone objects based on latitude and longitude then this configuration is not necessary.
|
11
|
+
class Configure
|
12
|
+
def self.username
|
13
|
+
@@username
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.username= username
|
17
|
+
@@username = username
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.begin
|
21
|
+
yield self
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Timezone
|
2
|
+
# Error messages that can be raised by this gem. To catch any related error message, simply use Error::Base.
|
3
|
+
#
|
4
|
+
# begin
|
5
|
+
# ...
|
6
|
+
# rescue Timezone::Error::Base => e
|
7
|
+
# puts "Timezone Error: #{e.message}"
|
8
|
+
# end
|
9
|
+
module Error
|
10
|
+
class Base < StandardError; end
|
11
|
+
class InvalidZone < Base; end
|
12
|
+
class NilZone < Base; end
|
13
|
+
class GeoNames < Base; end
|
14
|
+
class ParseTime < Base; end
|
15
|
+
end
|
16
|
+
end
|
data/lib/timezone/version.rb
CHANGED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'date'
|
3
|
+
require 'time'
|
4
|
+
require 'net/http'
|
5
|
+
require 'timezone/error'
|
6
|
+
require 'timezone/configure'
|
7
|
+
|
8
|
+
module Timezone
|
9
|
+
class Zone
|
10
|
+
attr_accessor :rules, :zone
|
11
|
+
|
12
|
+
# Create a new Timezone object.
|
13
|
+
#
|
14
|
+
# Timezone.new(options)
|
15
|
+
#
|
16
|
+
# :zone - The actual name of the zone. For example, Australia/Sydney or Americas/Los_Angeles.
|
17
|
+
# :lat, :lon - The latitude and longitude of the location.
|
18
|
+
# :latlon - The array of latitude and longitude of the location.
|
19
|
+
#
|
20
|
+
# If a latitude and longitude is passed in, the Timezone object will do a lookup for the actual zone
|
21
|
+
# name and then use that as a reference. It will then load the appropriate json timezone information
|
22
|
+
# for that zone, and compile a list of the timezone rules.
|
23
|
+
def initialize options
|
24
|
+
if options.has_key?(:lat) && options.has_key?(:lon)
|
25
|
+
options[:zone] = timezone_id options[:lat], options[:lon]
|
26
|
+
elsif options.has_key?(:latlon)
|
27
|
+
options[:zone] = timezone_id *options[:latlon]
|
28
|
+
end
|
29
|
+
|
30
|
+
raise Timezone::Error::NilZone, 'No zone was found. Please specify a zone.' if options[:zone].nil?
|
31
|
+
|
32
|
+
file = File.join File.expand_path(File.dirname(__FILE__)+'/../../data'), "#{options[:zone]}.json"
|
33
|
+
raise Timezone::Error::InvalidZone, "'#{options[:zone]}' is not a valid zone." unless File.exists?(file)
|
34
|
+
|
35
|
+
data = JSON.parse(open(file).read)
|
36
|
+
@rules = data['zone']
|
37
|
+
@zone = data['_zone'] || options[:zone]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Determine the time in the timezone.
|
41
|
+
#
|
42
|
+
# timezone.time(reference)
|
43
|
+
#
|
44
|
+
# reference - The Time you want to convert.
|
45
|
+
#
|
46
|
+
# The reference is converted to a UTC equivalent. That UTC equivalent is then used to lookup the appropriate
|
47
|
+
# offset in the timezone rules. Once the offset has been found that offset is added to the reference UTC time
|
48
|
+
# to calculate the reference time in the timezone.
|
49
|
+
def time reference
|
50
|
+
reference = reference.utc
|
51
|
+
rule = rules.detect{ |rule| _parsetime(rule['_from']) <= reference && _parsetime(rule['_to']) >= reference }
|
52
|
+
reference + rule['offset']
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def timezone_id lat, lon #:nodoc:
|
58
|
+
begin
|
59
|
+
response = Net::HTTP.get('ws.geonames.org', "/timezoneJSON?lat=#{lat}&lng=#{lon}&username=#{Timezone::Configure.username}")
|
60
|
+
JSON.parse(response)['timezoneId']
|
61
|
+
rescue Exception => e
|
62
|
+
raise Timezone::Error::GeoNames, e.message
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def _parsetime time #:nodoc:
|
67
|
+
begin
|
68
|
+
Time.strptime(time, "%Y-%m-%dT%H:%M:%SZ")
|
69
|
+
rescue Exception => e
|
70
|
+
raise Timezone::Error::ParseTime, e.message
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/test/timezone_test.rb
CHANGED
@@ -1,40 +1,43 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/../lib/timezone')
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/timezone/zone')
|
3
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/timezone/error')
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/timezone/configure')
|
2
5
|
require 'test/unit'
|
3
6
|
|
4
7
|
class TimezoneTest < Test::Unit::TestCase
|
5
8
|
|
6
9
|
def test_valid_timezone
|
7
10
|
assert_nothing_raised do
|
8
|
-
Timezone.new :zone => 'Australia/Sydney'
|
11
|
+
Timezone::Zone.new :zone => 'Australia/Sydney'
|
9
12
|
end
|
10
13
|
end
|
11
14
|
|
12
15
|
def test_nil_timezone
|
13
16
|
assert_raise Timezone::Error::NilZone do
|
14
|
-
Timezone.new :zone => nil
|
17
|
+
Timezone::Zone.new :zone => nil
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
18
21
|
def test_invalid_timezone
|
19
22
|
assert_raise Timezone::Error::InvalidZone do
|
20
|
-
Timezone.new :zone => 'Foo/Bar'
|
23
|
+
Timezone::Zone.new :zone => 'Foo/Bar'
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
24
27
|
def test_loading_GMT_timezone
|
25
|
-
timezone = Timezone.new :zone => 'GMT'
|
28
|
+
timezone = Timezone::Zone.new :zone => 'GMT'
|
26
29
|
assert_equal Time.now.utc.to_i, timezone.time(Time.now).to_i
|
27
30
|
end
|
28
31
|
|
29
32
|
def test_loading_historical_time
|
30
|
-
timezone = Timezone.new :zone => 'America/Los_Angeles'
|
33
|
+
timezone = Timezone::Zone.new :zone => 'America/Los_Angeles'
|
31
34
|
local = Time.strptime('2011-02-11T13:20:00Z', '%Y-%m-%dT%H:%M:%SZ')
|
32
35
|
utc = Time.strptime('2011-02-11T21:20:00Z', '%Y-%m-%dT%H:%M:%SZ')
|
33
36
|
assert_equal local.to_i, timezone.time(utc).to_i
|
34
37
|
end
|
35
38
|
|
36
39
|
def test_loading_half_hour_timezone
|
37
|
-
timezone = Timezone.new :zone => 'Asia/Kathmandu'
|
40
|
+
timezone = Timezone::Zone.new :zone => 'Asia/Kathmandu'
|
38
41
|
utc = Time.utc(2011, 1, 4, 3, 51, 29)
|
39
42
|
local = Time.utc(2011, 1, 4, 9, 36, 29)
|
40
43
|
assert_equal local.to_i, timezone.time(utc).to_i
|
@@ -42,12 +45,12 @@ class TimezoneTest < Test::Unit::TestCase
|
|
42
45
|
|
43
46
|
def test_using_lat_lon_coordinates
|
44
47
|
Timezone::Configure.begin { |c| c.username = 'timezone' }
|
45
|
-
timezone = Timezone.new :latlon => [-34.92771808058, 138.477041423321]
|
48
|
+
timezone = Timezone::Zone.new :latlon => [-34.92771808058, 138.477041423321]
|
46
49
|
assert_equal 'Australia/Adelaide', timezone.zone
|
47
50
|
end
|
48
51
|
|
49
52
|
def test_australian_timezone_with_dst
|
50
|
-
timezone = Timezone.new :zone => 'Australia/Adelaide'
|
53
|
+
timezone = Timezone::Zone.new :zone => 'Australia/Adelaide'
|
51
54
|
utc = Time.utc(2010, 12, 23, 19, 37, 15)
|
52
55
|
local = Time.utc(2010, 12, 24, 6, 7, 15)
|
53
56
|
assert_equal local.to_i, timezone.time(utc).to_i
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: timezone
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0
|
5
|
+
version: 0.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Pan Thomakos
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-02-
|
13
|
+
date: 2011-02-12 00:00:00 -08:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -490,7 +490,10 @@ files:
|
|
490
490
|
- data/Pacific/Wallis.json
|
491
491
|
- data/WET.json
|
492
492
|
- lib/timezone.rb
|
493
|
+
- lib/timezone/configure.rb
|
494
|
+
- lib/timezone/error.rb
|
493
495
|
- lib/timezone/version.rb
|
496
|
+
- lib/timezone/zone.rb
|
494
497
|
- test/timezone_test.rb
|
495
498
|
- timezone.gemspec
|
496
499
|
has_rdoc: true
|
@@ -520,6 +523,6 @@ rubyforge_project: timezone
|
|
520
523
|
rubygems_version: 1.5.0
|
521
524
|
signing_key:
|
522
525
|
specification_version: 3
|
523
|
-
summary: timezone-0.0
|
526
|
+
summary: timezone-0.1.0
|
524
527
|
test_files:
|
525
528
|
- test/timezone_test.rb
|