timezone 1.3.3 → 1.3.29
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 +5 -5
- data/.codeclimate.yml +15 -0
- data/.github/workflows/ci.yml +40 -0
- data/.rubocop.yml +24 -5
- data/CHANGES.markdown +107 -0
- data/CONTRIBUTING.markdown +10 -6
- data/README.markdown +5 -7
- data/Rakefile +3 -1
- data/benchmark.rb +16 -29
- data/data/Africa/Accra +1 -47
- data/data/Africa/Addis_Ababa +5 -4
- data/data/Africa/Algiers +2 -2
- data/data/Africa/Asmara +5 -4
- data/data/Africa/Asmera +5 -4
- data/data/Africa/Bangui +4 -1
- data/data/Africa/Blantyre +1 -1
- data/data/Africa/Brazzaville +4 -1
- data/data/Africa/Bujumbura +1 -1
- data/data/Africa/Cairo +32 -0
- data/data/Africa/Casablanca +8 -6
- data/data/Africa/Dar_es_Salaam +5 -4
- data/data/Africa/Djibouti +5 -4
- data/data/Africa/Douala +4 -1
- data/data/Africa/El_Aaiun +8 -6
- data/data/Africa/Gaborone +1 -1
- data/data/Africa/Harare +1 -1
- data/data/Africa/Juba +2 -1
- data/data/Africa/Kampala +5 -4
- data/data/Africa/Kigali +1 -1
- data/data/Africa/Kinshasa +4 -1
- data/data/Africa/Lagos +4 -1
- data/data/Africa/Libreville +4 -1
- data/data/Africa/Luanda +4 -1
- data/data/Africa/Lubumbashi +1 -1
- data/data/Africa/Lusaka +1 -1
- data/data/Africa/Malabo +4 -1
- data/data/Africa/Maputo +1 -1
- data/data/Africa/Mogadishu +5 -4
- data/data/Africa/Nairobi +5 -4
- data/data/Africa/Niamey +4 -1
- data/data/Africa/Porto-Novo +4 -1
- data/data/America/Anguilla +4 -1
- data/data/America/Antigua +4 -1
- data/data/America/Aruba +4 -2
- data/data/America/Asuncion +2 -29
- data/data/America/Atikokan +2 -7
- data/data/America/Bahia_Banderas +5 -39
- data/data/America/Barbados +8 -3
- data/data/America/Belize +44 -1
- data/data/America/Blanc-Sablon +3 -5
- data/data/America/Bogota +1 -1
- data/data/America/Cambridge_Bay +17 -3
- data/data/America/Campo_Grande +1 -40
- data/data/America/Cancun +7 -6
- data/data/America/Chihuahua +5 -37
- data/data/America/Ciudad_Juarez +94 -0
- data/data/America/Coral_Harbour +2 -7
- data/data/America/Coyhaique +134 -0
- data/data/America/Creston +11 -3
- data/data/America/Cuiaba +1 -40
- data/data/America/Curacao +4 -2
- data/data/America/Dawson +2 -38
- data/data/America/Detroit +5 -1
- data/data/America/Dominica +4 -1
- data/data/America/Edmonton +1 -5
- data/data/America/Ensenada +13 -7
- data/data/America/Godthab +31 -32
- data/data/America/Grand_Turk +1 -2
- data/data/America/Grenada +4 -1
- data/data/America/Guadeloupe +4 -1
- data/data/America/Guyana +4 -3
- data/data/America/Hermosillo +5 -7
- data/data/America/Indiana/Tell_City +9 -12
- data/data/America/Inuvik +17 -4
- data/data/America/Iqaluit +17 -3
- data/data/America/Kentucky/Louisville +4 -4
- data/data/America/Kralendijk +4 -2
- data/data/America/Louisville +4 -4
- data/data/America/Lower_Princes +4 -2
- data/data/America/Marigot +4 -1
- data/data/America/Matamoros +1 -1
- data/data/America/Mazatlan +5 -39
- data/data/America/Merida +3 -35
- data/data/America/Metlakatla +2 -1
- data/data/America/Mexico_City +4 -36
- data/data/America/Miquelon +2 -2
- data/data/America/Monterrey +6 -33
- data/data/America/Montreal +2 -2
- data/data/America/Montserrat +4 -1
- data/data/America/Nassau +86 -2
- data/data/America/Nipigon +103 -5
- data/data/America/Nuuk +119 -0
- data/data/America/Ojinaga +38 -38
- data/data/America/Pangnirtung +51 -38
- data/data/America/Port_of_Spain +4 -1
- data/data/America/Punta_Arenas +8 -7
- data/data/America/Rainy_River +118 -67
- data/data/America/Rankin_Inlet +17 -3
- data/data/America/Resolute +17 -3
- data/data/America/Santa_Isabel +13 -7
- data/data/America/Santiago +11 -11
- data/data/America/Sao_Paulo +1 -40
- data/data/America/Scoresbysund +30 -30
- data/data/America/St_Barthelemy +4 -1
- data/data/America/St_Kitts +4 -1
- data/data/America/St_Lucia +4 -1
- data/data/America/St_Thomas +4 -1
- data/data/America/St_Vincent +4 -1
- data/data/America/Thunder_Bay +99 -5
- data/data/America/Tijuana +13 -7
- data/data/America/Toronto +2 -2
- data/data/America/Tortola +4 -1
- data/data/America/Vancouver +2 -2
- data/data/America/Virgin +4 -1
- data/data/America/Whitehorse +4 -40
- data/data/America/Yellowknife +33 -5
- data/data/Antarctica/Casey +10 -0
- data/data/Antarctica/DumontDUrville +2 -3
- data/data/Antarctica/Macquarie +58 -3
- data/data/Antarctica/Syowa +1 -1
- data/data/Antarctica/Vostok +4 -1
- data/data/Arctic/Longyearbyen +23 -21
- data/data/Asia/Almaty +2 -1
- data/data/Asia/Amman +3 -35
- data/data/Asia/Brunei +18 -2
- data/data/Asia/Choibalsan +46 -47
- data/data/Asia/Chongqing +3 -1
- data/data/Asia/Chungking +3 -1
- data/data/Asia/Damascus +1 -33
- data/data/Asia/Dili +2 -2
- data/data/Asia/Gaza +46 -40
- data/data/Asia/Harbin +3 -1
- data/data/Asia/Hebron +46 -40
- data/data/Asia/Ho_Chi_Minh +4 -4
- data/data/Asia/Hong_Kong +19 -19
- data/data/Asia/Istanbul +22 -36
- data/data/Asia/Jerusalem +37 -31
- data/data/Asia/Kuala_Lumpur +3 -3
- data/data/Asia/Manila +14 -10
- data/data/Asia/Qostanay +2 -1
- data/data/Asia/Saigon +4 -4
- data/data/Asia/Seoul +9 -1
- data/data/Asia/Shanghai +3 -1
- data/data/Asia/Singapore +1 -1
- data/data/Asia/Tehran +8 -39
- data/data/Asia/Tel_Aviv +37 -31
- data/data/Atlantic/Azores +23 -28
- data/data/Atlantic/Bermuda +29 -2
- data/data/Atlantic/Jan_Mayen +23 -21
- data/data/Atlantic/Madeira +21 -28
- data/data/Atlantic/Reykjavik +1 -68
- data/data/Australia/ACT +9 -9
- data/data/Australia/Adelaide +9 -9
- data/data/Australia/Brisbane +9 -9
- data/data/Australia/Broken_Hill +9 -9
- data/data/Australia/Canberra +9 -9
- data/data/Australia/Currie +22 -10
- data/data/Australia/Darwin +8 -8
- data/data/Australia/Eucla +7 -7
- data/data/Australia/Hobart +12 -8
- data/data/Australia/Lindeman +9 -9
- data/data/Australia/Melbourne +9 -9
- data/data/Australia/NSW +9 -9
- data/data/Australia/North +8 -8
- data/data/Australia/Perth +7 -7
- data/data/Australia/Queensland +9 -9
- data/data/Australia/South +9 -9
- data/data/Australia/Sydney +9 -9
- data/data/Australia/Tasmania +12 -8
- data/data/Australia/Victoria +9 -9
- data/data/Australia/West +7 -7
- data/data/Australia/Yancowinna +9 -9
- data/data/Brazil/East +1 -40
- data/data/CET +56 -7
- data/data/CST6CDT +90 -3
- data/data/Canada/Eastern +2 -2
- data/data/Canada/Mountain +1 -5
- data/data/Canada/Pacific +2 -2
- data/data/Canada/Yukon +4 -40
- data/data/Chile/Continental +11 -11
- data/data/Chile/EasterIsland +2 -2
- data/data/EET +24 -8
- data/data/EST +3 -1
- data/data/EST5EDT +90 -3
- data/data/Egypt +32 -0
- data/data/Eire +2 -2
- data/data/Etc/UCT +1 -1
- data/data/Europe/Amsterdam +60 -55
- data/data/Europe/Brussels +2 -2
- data/data/Europe/Budapest +24 -24
- data/data/Europe/Copenhagen +23 -14
- data/data/Europe/Dublin +2 -2
- data/data/Europe/Istanbul +22 -36
- data/data/Europe/Kaliningrad +6 -5
- data/data/Europe/Kiev +8 -8
- data/data/Europe/Kirov +44 -44
- data/data/Europe/Kyiv +124 -0
- data/data/Europe/Lisbon +25 -22
- data/data/Europe/Luxembourg +38 -36
- data/data/Europe/Monaco +9 -10
- data/data/Europe/Oslo +23 -21
- data/data/Europe/Paris +3 -3
- data/data/Europe/Rome +2 -2
- data/data/Europe/San_Marino +2 -2
- data/data/Europe/Simferopol +10 -10
- data/data/Europe/Stockholm +28 -5
- data/data/Europe/Uzhgorod +18 -17
- data/data/Europe/Vatican +2 -2
- data/data/Europe/Vienna +2 -2
- data/data/Europe/Volgograd +48 -47
- data/data/Europe/Zaporozhye +17 -18
- data/data/HST +8 -1
- data/data/Hongkong +19 -19
- data/data/Iceland +1 -68
- data/data/Indian/Antananarivo +5 -4
- data/data/Indian/Christmas +2 -1
- data/data/Indian/Cocos +4 -1
- data/data/Indian/Comoro +5 -4
- data/data/Indian/Kerguelen +2 -1
- data/data/Indian/Mahe +1 -1
- data/data/Indian/Mayotte +5 -4
- data/data/Indian/Reunion +1 -1
- data/data/Iran +8 -39
- data/data/Israel +37 -31
- data/data/MET +188 -139
- data/data/MST +12 -1
- data/data/MST7MDT +12 -3
- data/data/Mexico/BajaNorte +13 -7
- data/data/Mexico/BajaSur +5 -39
- data/data/Mexico/General +4 -36
- data/data/PRC +3 -1
- data/data/PST8PDT +39 -2
- data/data/Pacific/Apia +1 -36
- data/data/Pacific/Chuuk +2 -6
- data/data/Pacific/Easter +2 -2
- data/data/Pacific/Efate +5 -3
- data/data/Pacific/Enderbury +2 -2
- data/data/Pacific/Fiji +5 -40
- data/data/Pacific/Funafuti +1 -1
- data/data/Pacific/Kanton +4 -0
- data/data/Pacific/Majuro +1 -7
- data/data/Pacific/Niue +2 -3
- data/data/Pacific/Norfolk +42 -3
- data/data/Pacific/Pohnpei +1 -7
- data/data/Pacific/Ponape +1 -7
- data/data/Pacific/Rarotonga +3 -2
- data/data/Pacific/Tongatapu +3 -3
- data/data/Pacific/Truk +2 -6
- data/data/Pacific/Wake +1 -1
- data/data/Pacific/Wallis +1 -1
- data/data/Pacific/Yap +2 -6
- data/data/Portugal +25 -22
- data/data/ROK +9 -1
- data/data/Singapore +1 -1
- data/data/Turkey +22 -36
- data/data/UCT +1 -1
- data/data/US/Michigan +5 -1
- data/data/WET +106 -4
- data/lib/timezone/error.rb +6 -0
- data/lib/timezone/loader.rb +8 -5
- data/lib/timezone/lookup/geonames.rb +1 -0
- data/lib/timezone/lookup/google.rb +3 -2
- data/lib/timezone/lookup.rb +3 -2
- data/lib/timezone/parser.rb +33 -18
- data/lib/timezone/version.rb +1 -1
- data/lib/timezone/zone.rb +17 -17
- data/test/test_timezone.rb +2 -4
- data/test/timezone/lookup/test_geonames.rb +16 -9
- data/test/timezone/lookup/test_google.rb +7 -2
- data/test/timezone/lookup/test_test.rb +1 -0
- data/test/timezone/test_lookup.rb +5 -5
- data/test/timezone/test_zone.rb +4 -4
- data/timezone.gemspec +10 -5
- metadata +62 -16
- data/.travis.yml +0 -12
- data/data/US/Pacific-New +0 -189
data/data/US/Michigan
CHANGED
@@ -5,7 +5,11 @@
|
|
5
5
|
3999600:EPT:1:-14400
|
6
6
|
81046800:EST:0:-18000
|
7
7
|
13302000:EDT:1:-14400
|
8
|
-
|
8
|
+
590540460:EST:0:-18000
|
9
|
+
11840340:EDT:1:-14400
|
10
|
+
15728400:EST:0:-18000
|
11
|
+
15721200:EDT:1:-14400
|
12
|
+
142131600:EST:0:-18000
|
9
13
|
15721200:EDT:1:-14400
|
10
14
|
6051600:EST:0:-18000
|
11
15
|
25398000:EDT:1:-14400
|
data/data/WET
CHANGED
@@ -1,11 +1,76 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
-1830384001:LMT:0:-2205
|
2
|
+
140828400:WET:0:0
|
3
|
+
11754000:WEST:1:3600
|
4
|
+
10368000:WET:0:0
|
5
|
+
19695600:WEST:1:3600
|
6
|
+
11840400:WET:0:0
|
7
|
+
19695600:WEST:1:3600
|
8
|
+
11840400:WET:0:0
|
9
|
+
19695600:WEST:1:3600
|
10
|
+
11926800:WET:0:0
|
11
|
+
19695600:WEST:1:3600
|
12
|
+
11840400:WET:0:0
|
13
|
+
19695600:WEST:1:3600
|
14
|
+
79056000:WET:0:0
|
15
|
+
14774400:WEST:1:3600
|
16
|
+
48384000:WET:0:0
|
17
|
+
14515200:WEST:1:3600
|
3
18
|
16329600:WET:0:0
|
19
|
+
15120000:WEST:1:3600
|
20
|
+
16934400:WET:0:0
|
21
|
+
15120000:WEST:1:3600
|
22
|
+
16934400:WET:0:0
|
23
|
+
14515200:WEST:1:3600
|
24
|
+
48384000:WET:0:0
|
25
|
+
14515200:WEST:1:3600
|
26
|
+
15724800:WET:0:0
|
27
|
+
15724800:WEST:1:3600
|
28
|
+
47779200:WET:0:0
|
4
29
|
15724800:WEST:1:3600
|
30
|
+
15120000:WET:0:0
|
31
|
+
16329600:WEST:1:3600
|
32
|
+
16934400:WET:0:0
|
33
|
+
14515200:WEST:1:3600
|
34
|
+
15724800:WET:0:0
|
35
|
+
15724800:WEST:1:3600
|
36
|
+
15120000:WET:0:0
|
37
|
+
16329600:WEST:1:3600
|
38
|
+
16934400:WET:0:0
|
39
|
+
18748800:WEST:1:3600
|
40
|
+
8467200:WET:0:0
|
41
|
+
19526400:WEST:1:3600
|
42
|
+
15552000:WET:0:0
|
43
|
+
15811200:WEST:1:3600
|
44
|
+
13824000:WET:0:0
|
45
|
+
3625200:WEST:1:3600
|
46
|
+
9676800:WEMT:1:7200
|
47
|
+
6051600:WEST:1:3600
|
48
|
+
12096000:WET:0:0
|
49
|
+
3020400:WEST:1:3600
|
50
|
+
11491200:WEMT:1:7200
|
51
|
+
5446800:WEST:1:3600
|
52
|
+
11491200:WET:0:0
|
53
|
+
3625200:WEST:1:3600
|
54
|
+
10886400:WEMT:1:7200
|
55
|
+
5446800:WEST:1:3600
|
56
|
+
11491200:WET:0:0
|
57
|
+
3625200:WEST:1:3600
|
58
|
+
10886400:WEMT:1:7200
|
59
|
+
5446800:WEST:1:3600
|
60
|
+
13910400:WET:0:0
|
61
|
+
15724800:WEST:1:3600
|
62
|
+
15735600:WET:0:0
|
63
|
+
15724800:WEST:1:3600
|
64
|
+
15724800:WET:0:0
|
65
|
+
15724800:WEST:1:3600
|
66
|
+
15724800:WET:0:0
|
67
|
+
15724800:WEST:1:3600
|
68
|
+
15724800:WET:0:0
|
69
|
+
15724800:WEST:1:3600
|
70
|
+
15724800:WET:0:0
|
71
|
+
16329600:WEST:1:3600
|
5
72
|
15724800:WET:0:0
|
6
73
|
15724800:WEST:1:3600
|
7
|
-
16329600:WET:0:0
|
8
|
-
15120000:WEST:1:3600
|
9
74
|
15724800:WET:0:0
|
10
75
|
15724800:WEST:1:3600
|
11
76
|
15724800:WET:0:0
|
@@ -34,9 +99,46 @@
|
|
34
99
|
15724800:WEST:1:3600
|
35
100
|
15724800:WET:0:0
|
36
101
|
15724800:WEST:1:3600
|
102
|
+
315093600:CET:0:3600
|
103
|
+
15724800:WET:0:0
|
104
|
+
15724800:WEST:1:3600
|
105
|
+
16333200:WET:0:0
|
106
|
+
15724800:WEST:1:3600
|
37
107
|
15724800:WET:0:0
|
38
108
|
15724800:WEST:1:3600
|
39
109
|
16329600:WET:0:0
|
110
|
+
15120000:WEST:1:3600
|
111
|
+
15721200:WET:0:0
|
112
|
+
15724800:WEST:1:3600
|
113
|
+
15724800:WET:0:0
|
114
|
+
15724800:WEST:1:3600
|
115
|
+
15724800:WET:0:0
|
116
|
+
15724800:WEST:1:3600
|
117
|
+
15724800:WET:0:0
|
118
|
+
16329600:WEST:1:3600
|
119
|
+
15724800:WET:0:0
|
120
|
+
15724800:WEST:1:3600
|
121
|
+
15728400:WET:0:0
|
122
|
+
15724800:WEST:1:3600
|
123
|
+
15724800:WET:0:0
|
124
|
+
15724800:WEST:1:3600
|
125
|
+
15724800:WET:0:0
|
126
|
+
15724800:WEST:1:3600
|
127
|
+
15724800:WET:0:0
|
128
|
+
15724800:WEST:1:3600
|
129
|
+
15724800:WET:0:0
|
130
|
+
16329600:WEST:1:3600
|
131
|
+
15724800:WET:0:0
|
132
|
+
15724800:WEST:1:3600
|
133
|
+
15724800:WET:0:0
|
134
|
+
15724800:WEST:1:3600
|
135
|
+
15724800:CET:0:3600
|
136
|
+
15724800:CEST:1:7200
|
137
|
+
15724800:CET:0:3600
|
138
|
+
15724800:CEST:1:7200
|
139
|
+
15724800:CET:0:3600
|
140
|
+
15724800:CEST:1:7200
|
141
|
+
16329600:CET:0:3600
|
40
142
|
18144000:WEST:1:3600
|
41
143
|
13305600:WET:0:0
|
42
144
|
18144000:WEST:1:3600
|
data/lib/timezone/error.rb
CHANGED
@@ -12,16 +12,22 @@ module Timezone
|
|
12
12
|
module Error
|
13
13
|
# Top-level error. All other timezone errors subclass this one.
|
14
14
|
class Base < StandardError; end
|
15
|
+
|
15
16
|
# Indicates an invalid timezone name.
|
16
17
|
class InvalidZone < Base; end
|
18
|
+
|
17
19
|
# Indicates a lookup failure.
|
18
20
|
class Lookup < Base; end
|
21
|
+
|
19
22
|
# Indicates an error during lookup using the geonames API.
|
20
23
|
class GeoNames < Lookup; end
|
24
|
+
|
21
25
|
# Indicates an error during lookup using the google API.
|
22
26
|
class Google < Lookup; end
|
27
|
+
|
23
28
|
# Indicates a missing stub during a test lookup.
|
24
29
|
class Test < Lookup; end
|
30
|
+
|
25
31
|
# Indicates an invalid configuration.
|
26
32
|
class InvalidConfig < Base; end
|
27
33
|
end
|
data/lib/timezone/loader.rb
CHANGED
@@ -2,18 +2,21 @@
|
|
2
2
|
|
3
3
|
require 'timezone/error'
|
4
4
|
|
5
|
-
module Timezone
|
5
|
+
module Timezone
|
6
6
|
# Responsible for loading and parsing timezone data from files.
|
7
7
|
module Loader
|
8
|
-
ZONE_FILE_PATH = File.expand_path(File.dirname(__FILE__)
|
8
|
+
ZONE_FILE_PATH = File.expand_path("#{File.dirname(__FILE__)}/../../data")
|
9
9
|
SOURCE_BIT = 0
|
10
10
|
|
11
|
+
@rules = {} # cache of loaded rules
|
12
|
+
|
11
13
|
class << self
|
12
14
|
def load(name)
|
13
|
-
|
15
|
+
@rules.fetch(name) do
|
16
|
+
raise ::Timezone::Error::InvalidZone unless valid?(name)
|
14
17
|
|
15
|
-
|
16
|
-
|
18
|
+
@rules[name] = parse_zone_data(get_zone_data(name))
|
19
|
+
end
|
17
20
|
end
|
18
21
|
|
19
22
|
def names
|
@@ -14,7 +14,7 @@ module Timezone
|
|
14
14
|
class Google < ::Timezone::Lookup::Basic
|
15
15
|
# Indicates that no time zone data could be found for the specified
|
16
16
|
# <lat, lng>. This can occur if the query is incomplete or ambiguous.
|
17
|
-
NO_TIMEZONE_INFORMATION = 'ZERO_RESULTS'
|
17
|
+
NO_TIMEZONE_INFORMATION = 'ZERO_RESULTS'
|
18
18
|
|
19
19
|
def initialize(config)
|
20
20
|
if config.api_key.nil?
|
@@ -34,7 +34,8 @@ module Timezone
|
|
34
34
|
raise(Timezone::Error::Google, '403 Forbidden')
|
35
35
|
end
|
36
36
|
|
37
|
-
return unless
|
37
|
+
return unless /^2\d\d$/.match?(response.code)
|
38
|
+
|
38
39
|
data = JSON.parse(response.body)
|
39
40
|
|
40
41
|
return if data['status'] == NO_TIMEZONE_INFORMATION
|
data/lib/timezone/lookup.rb
CHANGED
@@ -4,12 +4,13 @@ require 'timezone/lookup/geonames'
|
|
4
4
|
require 'timezone/lookup/google'
|
5
5
|
require 'timezone/lookup/test'
|
6
6
|
require 'timezone/net_http_client'
|
7
|
+
require 'ostruct'
|
7
8
|
|
8
9
|
module Timezone
|
9
10
|
# Configure timezone lookups.
|
10
11
|
module Lookup
|
11
12
|
class << self
|
12
|
-
MISSING_LOOKUP = 'No lookup configured'
|
13
|
+
MISSING_LOOKUP = 'No lookup configured'
|
13
14
|
private_constant :MISSING_LOOKUP
|
14
15
|
|
15
16
|
# Returns the lookup object
|
@@ -45,7 +46,7 @@ module Timezone
|
|
45
46
|
test: ::Timezone::Lookup::Test
|
46
47
|
}.freeze
|
47
48
|
|
48
|
-
INVALID_LOOKUP = 'Invalid lookup specified'
|
49
|
+
INVALID_LOOKUP = 'Invalid lookup specified'
|
49
50
|
|
50
51
|
attr_reader :config
|
51
52
|
|
data/lib/timezone/parser.rb
CHANGED
@@ -9,30 +9,45 @@ module Timezone
|
|
9
9
|
MIN_YEAR = -500
|
10
10
|
MAX_YEAR = 2039
|
11
11
|
|
12
|
-
LINE = /\s*(.+)\s*=\s*(.+)\s*isdst=(\d+)\s*gmtoff=([
|
12
|
+
LINE = /\s*(.+)\s*=\s*(.+)\s*isdst=(\d+)\s*gmtoff=([+\-]*\d+)/.freeze
|
13
13
|
|
14
|
-
|
14
|
+
# Bookkeeping files that we do not want to parse.
|
15
|
+
IGNORE = ['leapseconds', 'posixrules', 'tzdata.zi'].freeze
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
def initialize(zoneinfo = ZONEINFO_DIR)
|
19
|
-
@zoneinfo = zoneinfo
|
17
|
+
def initialize(root)
|
18
|
+
@config = Config.new(root)
|
20
19
|
end
|
21
20
|
|
22
21
|
def perform
|
23
22
|
FileUtils.rm_rf('data')
|
24
23
|
|
25
|
-
Dir["#{zoneinfo}
|
24
|
+
Dir["#{@config.zoneinfo}/**/*"].each do |file|
|
26
25
|
next if File.directory?(file)
|
26
|
+
next if file.end_with?('.tab')
|
27
|
+
next if IGNORE.include?(File.basename(file))
|
28
|
+
|
27
29
|
parse(file)
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
33
|
+
# Represents a timezone database config.
|
34
|
+
class Config
|
35
|
+
def initialize(root)
|
36
|
+
@root = root
|
37
|
+
@zoneinfo = File.join(@root, 'usr/share/zoneinfo')
|
38
|
+
@zdump = File.join(@root, 'usr/bin/zdump')
|
39
|
+
end
|
40
|
+
|
41
|
+
attr_reader :root, :zoneinfo, :zdump
|
42
|
+
end
|
43
|
+
|
44
|
+
private_constant :Config
|
45
|
+
|
31
46
|
# Represents a single timezone data file line for a reference timezone.
|
32
47
|
class RefLine
|
33
|
-
def initialize(
|
48
|
+
def initialize(config, file)
|
34
49
|
first =
|
35
|
-
|
50
|
+
`#{config.zdump} -i #{file}`
|
36
51
|
.split("\n")
|
37
52
|
.reject(&:empty?)
|
38
53
|
.reject { |line| line.start_with?('TZ=') }
|
@@ -51,7 +66,7 @@ module Timezone
|
|
51
66
|
def parse_offset(offset)
|
52
67
|
arity = offset.start_with?('-') ? -1 : 1
|
53
68
|
|
54
|
-
match = offset.match(/^[
|
69
|
+
match = offset.match(/^[\-+](\d{2})$/)
|
55
70
|
arity * match[1].to_i * 60 * 60
|
56
71
|
end
|
57
72
|
end
|
@@ -62,10 +77,10 @@ module Timezone
|
|
62
77
|
class Line
|
63
78
|
attr_accessor :source, :name, :dst, :offset
|
64
79
|
|
65
|
-
SOURCE_FORMAT = '%a %b %e %H:%M:%S %Y %Z'
|
80
|
+
SOURCE_FORMAT = '%a %b %e %H:%M:%S %Y %Z'
|
66
81
|
|
67
82
|
def initialize(match)
|
68
|
-
self.source = Time.strptime(match[1]
|
83
|
+
self.source = Time.strptime("#{match[1]}C", SOURCE_FORMAT).to_i
|
69
84
|
self.name = match[2].split(' ').last
|
70
85
|
self.dst = match[3].to_i
|
71
86
|
self.offset = match[4].to_i
|
@@ -85,15 +100,15 @@ module Timezone
|
|
85
100
|
private
|
86
101
|
|
87
102
|
def parse(file)
|
88
|
-
zone = file.gsub("#{zoneinfo}/
|
103
|
+
zone = file.gsub("#{@config.zoneinfo}/", '')
|
89
104
|
print "Parsing #{zone}... "
|
90
|
-
data = zdump(
|
105
|
+
data = zdump(file)
|
91
106
|
|
92
107
|
last = 0
|
93
108
|
result = []
|
94
109
|
|
95
110
|
data.split("\n").each do |line|
|
96
|
-
match = line.gsub(
|
111
|
+
match = line.gsub(/^#{file}\s+/, '').match(LINE)
|
97
112
|
next if match.nil?
|
98
113
|
|
99
114
|
line = Line.new(match)
|
@@ -112,14 +127,14 @@ module Timezone
|
|
112
127
|
result << line
|
113
128
|
end
|
114
129
|
|
115
|
-
result << RefLine.new(
|
130
|
+
result << RefLine.new(@config, file) if result.empty?
|
116
131
|
|
117
132
|
write(zone, result)
|
118
133
|
puts 'DONE'
|
119
134
|
end
|
120
135
|
|
121
|
-
def zdump(
|
122
|
-
|
136
|
+
def zdump(file)
|
137
|
+
`#{@config.zdump} -V -c #{MIN_YEAR},#{MAX_YEAR} #{file}`
|
123
138
|
end
|
124
139
|
|
125
140
|
def write(zone, data)
|
data/lib/timezone/version.rb
CHANGED
data/lib/timezone/zone.rb
CHANGED
@@ -6,7 +6,6 @@ require 'time'
|
|
6
6
|
|
7
7
|
require 'timezone/loader'
|
8
8
|
require 'timezone/error'
|
9
|
-
require 'timezone/loader'
|
10
9
|
|
11
10
|
module Timezone
|
12
11
|
# This object represents a real-world timezone. Each instance provides
|
@@ -179,10 +178,6 @@ module Timezone
|
|
179
178
|
|
180
179
|
private
|
181
180
|
|
182
|
-
def private_rules
|
183
|
-
@rules ||= Loader.load(name)
|
184
|
-
end
|
185
|
-
|
186
181
|
def sanitize(time)
|
187
182
|
time.to_time
|
188
183
|
end
|
@@ -200,11 +195,15 @@ module Timezone
|
|
200
195
|
|
201
196
|
def rule_for_local(local)
|
202
197
|
local = local.to_i
|
198
|
+
rules = Loader.load(name)
|
203
199
|
|
204
200
|
# For each rule, convert the local time into the UTC equivalent for
|
205
201
|
# that rule offset, and then check if the UTC time matches the rule.
|
206
|
-
index =
|
207
|
-
|
202
|
+
index =
|
203
|
+
binary_search(rules, local) do |t, r|
|
204
|
+
match?(t - r[OFFSET_BIT], r)
|
205
|
+
end
|
206
|
+
match = rules[index]
|
208
207
|
|
209
208
|
utc = local - match[OFFSET_BIT]
|
210
209
|
|
@@ -213,7 +212,7 @@ module Timezone
|
|
213
212
|
return RuleSet.new(:missing, [match]) if rule_for_utc(utc) != match
|
214
213
|
|
215
214
|
# If the match is the last rule, then return it.
|
216
|
-
return RuleSet.new(:single, [match]) if index ==
|
215
|
+
return RuleSet.new(:single, [match]) if index == rules.length - 1
|
217
216
|
|
218
217
|
# If the UTC equivalent time falls within the last hour(s) of the time
|
219
218
|
# change which were replayed during a fall-back in time, then return
|
@@ -234,10 +233,10 @@ module Timezone
|
|
234
233
|
last_hour =
|
235
234
|
match[SOURCE_BIT] -
|
236
235
|
match[OFFSET_BIT] +
|
237
|
-
|
236
|
+
rules[index + 1][OFFSET_BIT]
|
238
237
|
|
239
238
|
if utc > last_hour
|
240
|
-
RuleSet.new(:double,
|
239
|
+
RuleSet.new(:double, rules[index..(index + 1)])
|
241
240
|
else
|
242
241
|
RuleSet.new(:single, [match])
|
243
242
|
end
|
@@ -245,27 +244,28 @@ module Timezone
|
|
245
244
|
|
246
245
|
def rule_for_utc(time)
|
247
246
|
time = time.to_i
|
247
|
+
rules = Loader.load(name)
|
248
248
|
|
249
|
-
|
249
|
+
rules[binary_search(rules, time) { |t, r| match?(t, r) }]
|
250
250
|
end
|
251
251
|
|
252
252
|
# Find the first rule that matches using binary search.
|
253
|
-
def binary_search(time, from = 0, to = nil, &block)
|
254
|
-
to =
|
253
|
+
def binary_search(rules, time, from = 0, to = nil, &block)
|
254
|
+
to = rules.length - 1 if to.nil?
|
255
255
|
|
256
256
|
return from if from == to
|
257
257
|
|
258
258
|
mid = (from + to).div(2)
|
259
259
|
|
260
|
-
unless yield(time,
|
261
|
-
return binary_search(time, mid + 1, to, &block)
|
260
|
+
unless yield(time, rules[mid])
|
261
|
+
return binary_search(rules, time, mid + 1, to, &block)
|
262
262
|
end
|
263
263
|
|
264
264
|
return mid if mid.zero?
|
265
265
|
|
266
|
-
return mid unless yield(time,
|
266
|
+
return mid unless yield(time, rules[mid - 1])
|
267
267
|
|
268
|
-
binary_search(time, from, mid - 1, &block)
|
268
|
+
binary_search(rules, time, from, mid - 1, &block)
|
269
269
|
end
|
270
270
|
end
|
271
271
|
end
|
data/test/test_timezone.rb
CHANGED
@@ -32,13 +32,11 @@ class TestTimezone < ::Minitest::Test
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_fetch_warning
|
35
|
-
|
36
|
-
|
37
|
-
Timezone.stub(:warn, ->(_) { warning = true }) do
|
35
|
+
_out, err = capture_io do
|
38
36
|
Timezone.fetch('foo/bar', 'a') { 'b' }
|
39
37
|
end
|
40
38
|
|
41
|
-
|
39
|
+
assert_equal "warning: block supersedes default value argument\n", err
|
42
40
|
end
|
43
41
|
|
44
42
|
def test_lookup
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'timezone/lookup/geonames'
|
4
4
|
require 'minitest/autorun'
|
5
|
+
require 'ostruct'
|
5
6
|
require_relative '../../http_test_client'
|
6
7
|
|
7
8
|
class TestGeonames < ::Minitest::Test
|
@@ -19,6 +20,10 @@ class TestGeonames < ::Minitest::Test
|
|
19
20
|
}
|
20
21
|
end
|
21
22
|
|
23
|
+
def lookup_file(file_name, &block)
|
24
|
+
lookup(File.open(File.join(mock_path, file_name)).read, &block)
|
25
|
+
end
|
26
|
+
|
22
27
|
def lookup(body = nil, &_block)
|
23
28
|
config = OpenStruct.new
|
24
29
|
config.username = 'timezone'
|
@@ -40,23 +45,25 @@ class TestGeonames < ::Minitest::Test
|
|
40
45
|
end
|
41
46
|
|
42
47
|
def test_lookup
|
43
|
-
mine =
|
48
|
+
mine = lookup_file('/lat_lon_coords.txt')
|
44
49
|
|
45
50
|
assert_equal 'Australia/Adelaide', mine.lookup(*coordinates)
|
46
51
|
end
|
47
52
|
|
48
53
|
def test_lookup_with_etc
|
49
54
|
etc_data.each do |key, data|
|
50
|
-
|
51
|
-
|
55
|
+
mine = lookup_file("/lat_lon_coords_#{key}.txt") do |c|
|
56
|
+
c.offset_etc_zones = true
|
57
|
+
end
|
52
58
|
|
53
59
|
assert_equal data[:name], mine.lookup(*data[:coordinates])
|
54
60
|
end
|
55
61
|
end
|
56
62
|
|
57
63
|
def test_wrong_offset
|
58
|
-
|
59
|
-
|
64
|
+
mine = lookup_file('/lat_lon_coords_wrong_offset.txt') do |c|
|
65
|
+
c.offset_etc_zones = true
|
66
|
+
end
|
60
67
|
|
61
68
|
assert_nil mine.lookup(*coordinates)
|
62
69
|
end
|
@@ -80,7 +87,7 @@ class TestGeonames < ::Minitest::Test
|
|
80
87
|
end
|
81
88
|
|
82
89
|
def test_api_limit
|
83
|
-
mine =
|
90
|
+
mine = lookup_file('/api_limit_reached.json')
|
84
91
|
|
85
92
|
assert_exception(
|
86
93
|
mine,
|
@@ -90,19 +97,19 @@ class TestGeonames < ::Minitest::Test
|
|
90
97
|
end
|
91
98
|
|
92
99
|
def test_invalid_latlong
|
93
|
-
mine =
|
100
|
+
mine = lookup_file('/invalid_latlong.json')
|
94
101
|
|
95
102
|
assert_exception(mine, 'invalid lat/lng')
|
96
103
|
end
|
97
104
|
|
98
105
|
def test_no_result_found
|
99
|
-
mine =
|
106
|
+
mine = lookup_file('/no_result_found.json')
|
100
107
|
|
101
108
|
assert_nil(mine.lookup(10, 10))
|
102
109
|
end
|
103
110
|
|
104
111
|
def test_invalid_parameter
|
105
|
-
mine =
|
112
|
+
mine = lookup_file('/invalid_parameter.json')
|
106
113
|
|
107
114
|
assert_exception(mine, 'error parsing parameter')
|
108
115
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'timezone/lookup/google'
|
4
4
|
require 'minitest/autorun'
|
5
5
|
require 'timecop'
|
6
|
+
require 'ostruct'
|
6
7
|
require_relative '../../http_test_client'
|
7
8
|
|
8
9
|
class TestGoogle < ::Minitest::Test
|
@@ -12,6 +13,10 @@ class TestGoogle < ::Minitest::Test
|
|
12
13
|
[-34.92771808058, 138.477041423321]
|
13
14
|
end
|
14
15
|
|
16
|
+
def lookup_file(file_name, &block)
|
17
|
+
lookup(File.open(File.join(mock_path, file_name)).read, &block)
|
18
|
+
end
|
19
|
+
|
15
20
|
def lookup(body = nil, &_block)
|
16
21
|
config = OpenStruct.new
|
17
22
|
config.api_key = 'MTIzYWJj'
|
@@ -33,7 +38,7 @@ class TestGoogle < ::Minitest::Test
|
|
33
38
|
end
|
34
39
|
|
35
40
|
def test_google_using_lat_long_coordinates
|
36
|
-
mine =
|
41
|
+
mine = lookup_file('/google_lat_lon_coords.txt')
|
37
42
|
|
38
43
|
assert_equal 'Australia/Adelaide', mine.lookup(*coordinates)
|
39
44
|
end
|
@@ -76,7 +81,7 @@ class TestGoogle < ::Minitest::Test
|
|
76
81
|
end
|
77
82
|
|
78
83
|
def test_no_result_found
|
79
|
-
mine =
|
84
|
+
mine = lookup_file('/google_no_result_found.json')
|
80
85
|
|
81
86
|
assert_nil(mine.lookup(26.188703, -78.987053))
|
82
87
|
end
|
@@ -8,7 +8,7 @@ class TestLookup < ::Minitest::Test
|
|
8
8
|
Timezone::Lookup.config(:test)
|
9
9
|
|
10
10
|
assert_equal Timezone::Lookup::Test,
|
11
|
-
|
11
|
+
Timezone::Lookup.lookup.class
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_geonames_config
|
@@ -17,10 +17,10 @@ class TestLookup < ::Minitest::Test
|
|
17
17
|
end
|
18
18
|
|
19
19
|
assert_equal Timezone::Lookup::Geonames,
|
20
|
-
|
20
|
+
Timezone::Lookup.lookup.class
|
21
21
|
|
22
22
|
assert_equal Timezone::NetHTTPClient,
|
23
|
-
|
23
|
+
Timezone::Lookup.lookup.config.request_handler
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_google_config
|
@@ -29,10 +29,10 @@ class TestLookup < ::Minitest::Test
|
|
29
29
|
end
|
30
30
|
|
31
31
|
assert_equal Timezone::Lookup::Google,
|
32
|
-
|
32
|
+
Timezone::Lookup.lookup.class
|
33
33
|
|
34
34
|
assert_equal Timezone::NetHTTPClient,
|
35
|
-
|
35
|
+
Timezone::Lookup.lookup.config.request_handler
|
36
36
|
end
|
37
37
|
|
38
38
|
def test_custom_config
|
data/test/timezone/test_zone.rb
CHANGED
@@ -130,12 +130,12 @@ class TestZone < ::Minitest::Test
|
|
130
130
|
|
131
131
|
# http://www.timeanddate.com/worldclock/clockchange.html?n=2364&year=1940
|
132
132
|
def test_historical_time_change_in_hebron
|
133
|
-
local = Time.strptime('1940-
|
134
|
-
utc = Time.strptime('1940-05-
|
133
|
+
local = Time.strptime('1940-06-01T01:59:59 UTC', '%Y-%m-%dT%H:%M:%S %Z')
|
134
|
+
utc = Time.strptime('1940-05-31T23:59:59 UTC', '%Y-%m-%dT%H:%M:%S %Z')
|
135
135
|
assert_equal local.to_i, zone('Asia/Hebron').time(utc).to_i
|
136
136
|
|
137
|
-
local = Time.strptime('1940-06-
|
138
|
-
utc = Time.strptime('1940-
|
137
|
+
local = Time.strptime('1940-06-01T03:00:00 UTC', '%Y-%m-%dT%H:%M:%S %Z')
|
138
|
+
utc = Time.strptime('1940-06-01T00:00:00 UTC', '%Y-%m-%dT%H:%M:%S %Z')
|
139
139
|
assert_equal local.to_i, zone('Asia/Hebron').time(utc).to_i
|
140
140
|
end
|
141
141
|
|