TimezoneParser 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.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/.yardopts +1 -0
- data/Gemfile +10 -0
- data/README.md +133 -0
- data/Rakefile +160 -0
- data/TimezoneParser.gemspec +40 -0
- data/UNLICENSE +24 -0
- data/data/version.yml +5 -0
- data/lib/timezone_parser.rb +159 -0
- data/lib/timezone_parser/abbreviation.rb +120 -0
- data/lib/timezone_parser/data.rb +121 -0
- data/lib/timezone_parser/data/cldr.rb +175 -0
- data/lib/timezone_parser/data/storage.rb +172 -0
- data/lib/timezone_parser/data/tzinfo.rb +151 -0
- data/lib/timezone_parser/data/windows.rb +124 -0
- data/lib/timezone_parser/rails_zone.rb +178 -0
- data/lib/timezone_parser/timezone.rb +159 -0
- data/lib/timezone_parser/version.rb +5 -0
- data/lib/timezone_parser/windows_zone.rb +169 -0
- data/lib/timezone_parser/zone_info.rb +70 -0
- data/spec/abbreviation_spec.rb +122 -0
- data/spec/rails_zone_spec.rb +84 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/timezone_parser_spec.rb +76 -0
- data/spec/timezone_spec.rb +108 -0
- data/spec/windows_zone_spec.rb +81 -0
- metadata +228 -0
@@ -0,0 +1,120 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module TimezoneParser
|
4
|
+
# Timezone abbreviation
|
5
|
+
class Abbreviation < ZoneInfo
|
6
|
+
protected
|
7
|
+
@@Regions = []
|
8
|
+
|
9
|
+
public
|
10
|
+
# Regions which will be used for Abbreviation methods if not specified there
|
11
|
+
#
|
12
|
+
# Each region is either ISO 3166-1 alpha-2 code
|
13
|
+
# @return [Array<String>] list containing region identifiers
|
14
|
+
# @see http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
|
15
|
+
def self.Regions
|
16
|
+
@@Regions
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :Regions
|
20
|
+
attr_accessor :Type
|
21
|
+
|
22
|
+
# Abbreviation instance
|
23
|
+
# @param abbreviation [String] Timezone abbreviation
|
24
|
+
def initialize(abbreviation)
|
25
|
+
@Abbreviation = abbreviation
|
26
|
+
@Data = Data.new
|
27
|
+
setTime
|
28
|
+
set(@@Regions.dup, nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set regions and type
|
32
|
+
# @param regions [Array<String>] filter for these regions
|
33
|
+
# @param type [Symbol] filter by type, :standard time or :daylight
|
34
|
+
# @return [Abbreviation] self
|
35
|
+
# @see Regions
|
36
|
+
def set(regions = nil, type = nil)
|
37
|
+
@Regions = regions unless regions.nil?
|
38
|
+
@Type = type.to_sym if type
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
# Check if abbreviation is valid
|
43
|
+
# @return [Boolean] whether abbreviation is valid
|
44
|
+
def isValid?
|
45
|
+
Data::Storage.Abbreviations.has_key?(@Abbreviation)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Abbreviation data
|
49
|
+
# @return [Data] data
|
50
|
+
def getData
|
51
|
+
unless @Loaded
|
52
|
+
@Loaded = true
|
53
|
+
if isValid?
|
54
|
+
data = Data::Storage.Abbreviations[@Abbreviation]
|
55
|
+
if data.count == 1
|
56
|
+
@Data.processEntry(data.first, @ToTime, @FromTime, @Regions)
|
57
|
+
return @Data
|
58
|
+
end
|
59
|
+
entries = Data.filterData(data, @ToTime, @FromTime, @Type, @Regions)
|
60
|
+
entries.each do |entry|
|
61
|
+
@Data.processEntry(entry, @ToTime, @FromTime, @Regions)
|
62
|
+
end
|
63
|
+
return @Data
|
64
|
+
end
|
65
|
+
end
|
66
|
+
@Data
|
67
|
+
end
|
68
|
+
|
69
|
+
# Get UTC offsets in seconds
|
70
|
+
# @return [Array<Fixnum>] list of timezone offsets in seconds
|
71
|
+
def getOffsets
|
72
|
+
unless @Offsets
|
73
|
+
@Offsets = getData.Offsets.to_a
|
74
|
+
if @Offsets.empty? and not getTimezones.empty?
|
75
|
+
types = nil
|
76
|
+
types = [@Type] if @Type
|
77
|
+
@Offsets = @Data.findOffsets(@ToTime, @FromTime, @Regions, types).to_a
|
78
|
+
end
|
79
|
+
end
|
80
|
+
@Offsets
|
81
|
+
end
|
82
|
+
|
83
|
+
# Check if given Timezone abbreviation is a valid timezone
|
84
|
+
# @param abbreviation [String] Timezone abbreviation
|
85
|
+
# @return [Boolean] whether Timezone is valid
|
86
|
+
def self.isValid?(abbreviation)
|
87
|
+
Data::Storage.Abbreviations.has_key?(abbreviation)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Get UTC offsets in seconds for given Timezone abbreviation
|
91
|
+
# @param abbreviation [String] Timezone abbreviation
|
92
|
+
# @param toTime [DateTime] look for offsets which came into effect before this date, exclusive
|
93
|
+
# @param fromTime [DateTime] look for offsets which came into effect at this date, inclusive
|
94
|
+
# @param regions [Array<String>] look for offsets only for these regions
|
95
|
+
# @param type [Symbol] specify whether offset should be :standard time or :daylight
|
96
|
+
# @return [Array<Fixnum>] list of timezone offsets in seconds
|
97
|
+
# @see Regions
|
98
|
+
def self.getOffsets(abbreviation, toTime = nil, fromTime = nil, regions = nil, type = nil)
|
99
|
+
self.new(abbreviation).setTime(toTime, fromTime).set(regions, type).getOffsets
|
100
|
+
end
|
101
|
+
|
102
|
+
# Get Timezone identifiers for given Timezone abbreviation
|
103
|
+
# @param abbreviation [String] Timezone abbreviation
|
104
|
+
# @param toTime [DateTime] look for timezones which came into effect before this date, exclusive
|
105
|
+
# @param fromTime [DateTime] look for timezones which came into effect at this date, inclusive
|
106
|
+
# @param regions [Array<String>] look for timezones only for these regions
|
107
|
+
# @param type [Symbol] specify whether timezones should be :standard time or :daylight
|
108
|
+
# @return [Array<String>] list of timezone identifiers
|
109
|
+
# @see Regions
|
110
|
+
def self.getTimezones(abbreviation, toTime = nil, fromTime = nil, regions = nil, type = nil)
|
111
|
+
self.new(abbreviation).setTime(toTime, fromTime).set(regions, type).getTimezones
|
112
|
+
end
|
113
|
+
|
114
|
+
# Get Metazone identifiers for given Timezone abbreviation
|
115
|
+
# @param abbreviation [String] Timezone abbreviation
|
116
|
+
def self.getMetazones(abbreviation)
|
117
|
+
self.new(abbreviation).getMetazones
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'pathname'
|
3
|
+
require 'set'
|
4
|
+
require 'tzinfo'
|
5
|
+
require 'timezone_parser/data/storage'
|
6
|
+
|
7
|
+
module TimezoneParser
|
8
|
+
# Timezone data
|
9
|
+
class Data
|
10
|
+
# Library Root directory
|
11
|
+
RootDir = Pathname.new(__FILE__).realpath.dirname.parent.parent
|
12
|
+
# Path to Data directory
|
13
|
+
DataDir = RootDir + 'data'
|
14
|
+
# Path to Vendor directory
|
15
|
+
VendorDir = RootDir + 'vendor'
|
16
|
+
|
17
|
+
attr_reader :Offsets
|
18
|
+
attr_reader :Timezones
|
19
|
+
attr_reader :Types
|
20
|
+
attr_reader :Metazones
|
21
|
+
def initialize
|
22
|
+
@Offsets = SortedSet.new
|
23
|
+
@Timezones = SortedSet.new
|
24
|
+
@Types = SortedSet.new
|
25
|
+
@Metazones = SortedSet.new
|
26
|
+
end
|
27
|
+
|
28
|
+
def processEntry(entry, toTime, fromTime, regions = [])
|
29
|
+
@Timezones += entry['Timezones'] if entry['Timezones']
|
30
|
+
@Offsets << entry['Offset'] if entry['Offset']
|
31
|
+
@Types += entry['Types'].map(&:to_sym) if entry['Types']
|
32
|
+
if entry.has_key?('Metazones')
|
33
|
+
entry['Metazones'].each do |zone|
|
34
|
+
@Metazones << zone
|
35
|
+
@Timezones += Storage.getTimezones(zone, toTime, fromTime, regions)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def findOffsets(toTime, fromTime, regions = nil, types = nil)
|
42
|
+
types = @Types.to_a unless types
|
43
|
+
types = [:daylight, :standard] if types.empty?
|
44
|
+
@Timezones.each do |timezone|
|
45
|
+
if regions and not regions.empty?
|
46
|
+
timezoneRegions = Data::Storage.TimezoneCountries[timezone]
|
47
|
+
next if timezoneRegions and (timezoneRegions & regions).empty?
|
48
|
+
end
|
49
|
+
begin
|
50
|
+
tz = TZInfo::Timezone.get(timezone)
|
51
|
+
rescue TZInfo::InvalidTimezoneIdentifier
|
52
|
+
tz = nil
|
53
|
+
end
|
54
|
+
next unless tz
|
55
|
+
offsets = []
|
56
|
+
ts = false
|
57
|
+
tz.transitions_up_to(toTime, fromTime).each do |transition|
|
58
|
+
ts = true
|
59
|
+
self.class.addOffset(offsets, transition.offset, types)
|
60
|
+
end
|
61
|
+
self.class.addOffset(offsets, tz.period_for_utc(toTime - 0.001).offset, types) unless ts
|
62
|
+
@Offsets += offsets
|
63
|
+
end
|
64
|
+
@Offsets
|
65
|
+
end
|
66
|
+
|
67
|
+
# Load data entries which match specified time
|
68
|
+
# @param data [Array<Hash>] array of entries
|
69
|
+
# @param toTime [DateTime] entries before this date, exclusive
|
70
|
+
# @param fromTime [DateTime] entries after/at this date, inclusive
|
71
|
+
# @return [Array<Hash>] resulting array containing filtered entries
|
72
|
+
def self.loadEntries(data, toTime, fromTime, offsets = false)
|
73
|
+
result = []
|
74
|
+
data.each do |entry|
|
75
|
+
result << entry if (entry['From'] && entry['To'] and toTime > entry['From'] and fromTime < entry['To']) or
|
76
|
+
(entry['From'] && !entry['To'] and toTime > entry['From']) or
|
77
|
+
(!entry['From'] && entry['To'] and fromTime < entry['To']) or
|
78
|
+
(!entry['From'] && !entry['To'])
|
79
|
+
end
|
80
|
+
result.each do |entry|
|
81
|
+
return result if not offsets or (offsets and entry['Offset'])
|
82
|
+
end
|
83
|
+
data.each_index do |i|
|
84
|
+
entry = data[i]
|
85
|
+
nextentry = offsets ? getNextEntry(data, i) : data[i+1]
|
86
|
+
result << entry if ( entry['From'] && entry['To'] and toTime > entry['From'] and fromTime < entry['To'] ) or
|
87
|
+
( entry['To'] and ( (nextentry.nil? and fromTime >= entry['To']) or
|
88
|
+
(nextentry and nextentry['From'] and fromTime >= entry['To'] and toTime <= nextentry['From']) or
|
89
|
+
(!entry['From'] and fromTime < entry['To']) ) ) or
|
90
|
+
( entry['From'] and ( (i.zero? and toTime <= entry['From']) or (!entry['To'] and toTime > entry['From']) ) )
|
91
|
+
end
|
92
|
+
result
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.filterData(data, toTime, fromTime, type, regions)
|
96
|
+
entries = []
|
97
|
+
data.each do |entry|
|
98
|
+
next if type and entry['Types'] and not entry['Types'].include?(type)
|
99
|
+
next if not regions.empty? and entry['Countries'] and (entry['Countries'] & regions).empty?
|
100
|
+
entries << entry
|
101
|
+
end
|
102
|
+
loadEntries(entries, toTime, fromTime, true)
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
|
107
|
+
def self.getNextEntry(data, i)
|
108
|
+
j = 1
|
109
|
+
begin
|
110
|
+
entry = data[i+j]
|
111
|
+
j += 1
|
112
|
+
end until entry.nil? or (entry and entry['Offset'])
|
113
|
+
entry
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.addOffset(offsets, offset, types)
|
117
|
+
offsets << offset.utc_total_offset if (offset.dst? and types.include?(:daylight)) or (not offset.dst? and types.include?(:standard))
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'cldr'
|
3
|
+
require 'cldr/download'
|
4
|
+
require 'cldr/export/data'
|
5
|
+
require 'cldr/export/data/timezones'
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
module TimezoneParser
|
9
|
+
# CLDR module
|
10
|
+
module CLDR
|
11
|
+
|
12
|
+
# Data directory
|
13
|
+
DataDir = Pathname.new(Cldr::Export::Data.dir)
|
14
|
+
|
15
|
+
protected
|
16
|
+
@@Version = nil
|
17
|
+
|
18
|
+
public
|
19
|
+
def self.download(source = 'http://unicode.org/Public/cldr/latest/core.zip', target = nil)
|
20
|
+
Cldr.download(source, target)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.updateHash(hash, name, data)
|
24
|
+
hash[name] ||= []
|
25
|
+
hash[name] << data.to_s
|
26
|
+
hash[name].uniq!
|
27
|
+
hash[name].sort!
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.getVersion(source = DataDir)
|
32
|
+
return @@Version if @@Version
|
33
|
+
content = File.read(source + 'dtd' + 'ldml.dtd')
|
34
|
+
content.gsub!(/<!--.*?-->/, '')
|
35
|
+
data = content.match(/\s+cldrVersion\s+[\#\w\s]+\s+"(\d+)"\s*\>/)
|
36
|
+
@@Version = data[1].to_i if data
|
37
|
+
@@Version
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.getTimezones
|
41
|
+
timezones = { }
|
42
|
+
Cldr::Export::Data.locales.sort.each do |locale|
|
43
|
+
tz = Cldr::Export::Data::Timezones.new(locale)
|
44
|
+
next if tz.timezones.empty? and tz.metazones.empty?
|
45
|
+
|
46
|
+
tz.timezones.each do |timezone, data|
|
47
|
+
next if timezone == :'Etc/Unknown' or data[:city].nil?
|
48
|
+
city = data[:city].to_s.encode(Encoding::UTF_8).chomp.strip
|
49
|
+
timezones[locale] ||= {}
|
50
|
+
timezones[locale][city] ||= {}
|
51
|
+
self.updateHash(timezones[locale][city], 'Timezones', timezone)
|
52
|
+
data[:long].to_a.each do |type, name|
|
53
|
+
name = name.to_s.encode(Encoding::UTF_8).chomp.strip
|
54
|
+
type = type.to_s.encode(Encoding::UTF_8)
|
55
|
+
timezones[locale][name] ||= {}
|
56
|
+
if type == 'generic'
|
57
|
+
self.updateHash(timezones[locale][name], 'Types', 'standard')
|
58
|
+
self.updateHash(timezones[locale][name], 'Types', 'daylight')
|
59
|
+
else
|
60
|
+
self.updateHash(timezones[locale][name], 'Types', type)
|
61
|
+
end
|
62
|
+
self.updateHash(timezones[locale][name], 'Timezones', timezone.to_s.encode(Encoding::UTF_8))
|
63
|
+
end
|
64
|
+
end
|
65
|
+
tz.metazones.each do |metazone, data|
|
66
|
+
data[:long].to_a.each do |type, name|
|
67
|
+
name = name.to_s.encode(Encoding::UTF_8).chomp.strip
|
68
|
+
next if name.empty?
|
69
|
+
type = type.to_s.encode(Encoding::UTF_8)
|
70
|
+
timezones[locale] ||= {}
|
71
|
+
timezones[locale][name] ||= {}
|
72
|
+
if type == 'generic'
|
73
|
+
self.updateHash(timezones[locale][name], 'Types', 'standard')
|
74
|
+
self.updateHash(timezones[locale][name], 'Types', 'daylight')
|
75
|
+
else
|
76
|
+
self.updateHash(timezones[locale][name], 'Types', type)
|
77
|
+
end
|
78
|
+
self.updateHash(timezones[locale][name], 'Metazones', metazone.to_s.encode(Encoding::UTF_8))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
timezones[locale] = Hash[timezones[locale].to_a.sort_by { |d| d.first } ] if timezones[locale]
|
82
|
+
end
|
83
|
+
timezones
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.updateAbbreviations(abbreviations)
|
87
|
+
Cldr::Export::Data.locales.sort.each do |locale|
|
88
|
+
tz = Cldr::Export::Data::Timezones.new(locale)
|
89
|
+
next if tz.timezones.empty? and tz.metazones.empty?
|
90
|
+
tz.timezones.each do |timezone, data|
|
91
|
+
data[:short].to_a.each do |type, name|
|
92
|
+
next if name == '∅∅∅'
|
93
|
+
name = name.chomp.strip
|
94
|
+
type = type.to_s.encode(Encoding::UTF_8)
|
95
|
+
abbreviations[name] ||= []
|
96
|
+
data = {}
|
97
|
+
add = true
|
98
|
+
abbreviations[name].each_index do |i|
|
99
|
+
next unless abbreviations[name][i]['Offset'].nil?
|
100
|
+
data = abbreviations[name][i]
|
101
|
+
add = false
|
102
|
+
break
|
103
|
+
end
|
104
|
+
if type == 'generic'
|
105
|
+
self.updateHash(data, 'Types', 'standard')
|
106
|
+
self.updateHash(data, 'Types', 'daylight')
|
107
|
+
else
|
108
|
+
self.updateHash(data, 'Types', type)
|
109
|
+
end
|
110
|
+
self.updateHash(data, 'Timezones', timezone)
|
111
|
+
abbreviations[name] << data if add
|
112
|
+
end
|
113
|
+
end
|
114
|
+
tz.metazones.each do |metazone, data|
|
115
|
+
data[:short].to_a.each do |type, name|
|
116
|
+
next if name == '∅∅∅'
|
117
|
+
name = name.chomp.strip
|
118
|
+
type = type.to_s.encode(Encoding::UTF_8)
|
119
|
+
abbreviations[name] ||= []
|
120
|
+
data = {}
|
121
|
+
add = true
|
122
|
+
abbreviations[name].each_index do |i|
|
123
|
+
next unless abbreviations[name][i]['Offset'].nil?
|
124
|
+
data = abbreviations[name][i]
|
125
|
+
add = false
|
126
|
+
break
|
127
|
+
end
|
128
|
+
if type == 'generic'
|
129
|
+
self.updateHash(data, 'Types', 'standard')
|
130
|
+
self.updateHash(data, 'Types', 'daylight')
|
131
|
+
else
|
132
|
+
self.updateHash(data, 'Types', type)
|
133
|
+
end
|
134
|
+
self.updateHash(data, 'Metazones', metazone)
|
135
|
+
abbreviations[name] << data if add
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
abbreviations = Hash[abbreviations.to_a.sort_by { |d| d.first } ]
|
140
|
+
abbreviations
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.getMetazones
|
144
|
+
zones = {}
|
145
|
+
Cldr::Export::Data::Metazones.new[:timezones].each do |timezone, zonedata|
|
146
|
+
zonedata.each do |data|
|
147
|
+
entry = {}
|
148
|
+
add = true
|
149
|
+
zones[data['metazone']] ||= []
|
150
|
+
zones[data['metazone']].each_index do |i|
|
151
|
+
next if zones[data['metazone']][i]['From'].to_s != data['from'].to_s or zones[data['metazone']][i]['To'].to_s != data['to'].to_s
|
152
|
+
entry = zones[data['metazone']][i]
|
153
|
+
add = false
|
154
|
+
break
|
155
|
+
end
|
156
|
+
self.updateHash(entry, 'Timezones', timezone)
|
157
|
+
if add
|
158
|
+
entry['From'] = data['from'].to_s if data['from']
|
159
|
+
entry['To'] = data['to'].to_s if data['to']
|
160
|
+
zones[data['metazone']] << entry
|
161
|
+
end
|
162
|
+
zones[data['metazone']].sort_by! { |d| [d['To'] ? d['To'] : 'zzzz', d['From'] ? d['From'] : ''] }
|
163
|
+
end
|
164
|
+
end
|
165
|
+
zones = Hash[zones.to_a.sort_by { |d| d.first } ]
|
166
|
+
zones
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.getWindowsZones
|
170
|
+
zones = Cldr::Export::Data::WindowsZones.new
|
171
|
+
zones = Hash[zones.to_a.sort_by { |d| d.first } ]
|
172
|
+
zones
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'yaml'
|
3
|
+
require 'date'
|
4
|
+
require 'insensitive_hash'
|
5
|
+
|
6
|
+
module TimezoneParser
|
7
|
+
class Data
|
8
|
+
# Timezone data Storage class
|
9
|
+
class Storage
|
10
|
+
protected
|
11
|
+
@@Abbreviations = nil
|
12
|
+
@@Timezones = nil
|
13
|
+
@@TimezoneCountries = nil
|
14
|
+
@@Metazones = nil
|
15
|
+
@@WindowsZones = nil
|
16
|
+
@@WindowsTimezones = nil
|
17
|
+
@@WindowsOffsets = nil
|
18
|
+
@@RailsZones = nil
|
19
|
+
@@RailsTranslated = nil
|
20
|
+
|
21
|
+
public
|
22
|
+
def self.Abbreviations
|
23
|
+
unless @@Abbreviations
|
24
|
+
@@Abbreviations = Marshal.load(File.open(Data::DataDir + 'abbreviations.dat')).insensitive
|
25
|
+
@@Abbreviations.each do |abbr, data|
|
26
|
+
proccessData(data)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@@Abbreviations
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.Timezones
|
33
|
+
unless @@Timezones
|
34
|
+
@@Timezones = Marshal.load(File.open(Data::DataDir + 'timezones.dat')).insensitive
|
35
|
+
end
|
36
|
+
@@Timezones
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.TimezoneCountries
|
40
|
+
unless @@TimezoneCountries
|
41
|
+
@@TimezoneCountries = Marshal.load(File.open(Data::DataDir + 'countries.dat')).insensitive
|
42
|
+
end
|
43
|
+
@@TimezoneCountries
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.Metazones
|
47
|
+
unless @@Metazones
|
48
|
+
@@Metazones = Marshal.load(File.open(Data::DataDir + 'metazones.dat')).insensitive
|
49
|
+
@@Metazones.each do |zone, data|
|
50
|
+
proccessData(data)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
@@Metazones
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.WindowsZones
|
57
|
+
unless @@WindowsZones
|
58
|
+
@@WindowsZones = Marshal.load(File.open(Data::DataDir + 'windows_zonenames.dat')).insensitive
|
59
|
+
end
|
60
|
+
@@WindowsZones
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.WindowsTimezones
|
64
|
+
unless @@WindowsTimezones
|
65
|
+
@@WindowsTimezones = Marshal.load(File.open(Data::DataDir + 'windows_timezones.dat')).insensitive
|
66
|
+
end
|
67
|
+
@@WindowsTimezones
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.WindowsOffsets
|
71
|
+
unless @@WindowsOffsets
|
72
|
+
@@WindowsOffsets = Marshal.load(File.open(Data::DataDir + 'windows_offsets.dat')).insensitive
|
73
|
+
end
|
74
|
+
@@WindowsOffsets
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.RailsZones
|
78
|
+
unless @@RailsZones
|
79
|
+
@@RailsZones = Marshal.load(File.open(Data::DataDir + 'rails.dat')).insensitive
|
80
|
+
end
|
81
|
+
@@RailsZones
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.RailsTranslated
|
85
|
+
unless @@RailsTranslated
|
86
|
+
@@RailsTranslated = Marshal.load(File.open(Data::DataDir + 'rails_i18n.dat')).insensitive
|
87
|
+
end
|
88
|
+
@@RailsTranslated
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.preload(modules)
|
92
|
+
preloaded = false
|
93
|
+
modules.each do |m|
|
94
|
+
case m
|
95
|
+
when :Abbreviations
|
96
|
+
self.Abbreviations
|
97
|
+
self.Metazones
|
98
|
+
preloaded = true
|
99
|
+
when :Timezones
|
100
|
+
self.Timezones
|
101
|
+
self.Metazones
|
102
|
+
preloaded = true
|
103
|
+
when :WindowsZones
|
104
|
+
self.WindowsZones
|
105
|
+
self.WindowsTimezones
|
106
|
+
self.WindowsOffsets
|
107
|
+
preloaded = true
|
108
|
+
when :RailsZones
|
109
|
+
self.RailsZones
|
110
|
+
self.RailsTranslated
|
111
|
+
preloaded = true
|
112
|
+
end
|
113
|
+
end
|
114
|
+
preloaded
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.getTimezones(metazone, toTime, fromTime, regions = [])
|
118
|
+
timezones = SortedSet.new
|
119
|
+
if self.Metazones.has_key?(metazone)
|
120
|
+
entries = Data::loadEntries(self.Metazones[metazone], toTime, fromTime)
|
121
|
+
entries.each do |entry|
|
122
|
+
add = true
|
123
|
+
timezones += entry['Timezones'].select do |timezone|
|
124
|
+
if regions.empty?
|
125
|
+
true
|
126
|
+
else
|
127
|
+
timezoneRegions = self.TimezoneCountries[timezone]
|
128
|
+
timezoneRegions && !(regions & timezoneRegions).empty?
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
timezones
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.getTimezones2(zone, regions = [])
|
137
|
+
timezones = SortedSet.new
|
138
|
+
if self.WindowsTimezones.has_key?(zone)
|
139
|
+
entries = self.WindowsTimezones[zone]
|
140
|
+
regions = entries.keys if regions.empty?
|
141
|
+
regions.each do |region|
|
142
|
+
next unless entries.has_key?(region)
|
143
|
+
timezones += entries[region]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
timezones
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.getOffsets(zone, types = [])
|
150
|
+
offsets = SortedSet.new
|
151
|
+
if self.WindowsOffsets.has_key?(zone)
|
152
|
+
data = self.WindowsOffsets[zone]
|
153
|
+
types = [:standard, :daylight] if types.empty?
|
154
|
+
types.each do |type|
|
155
|
+
next unless data.has_key?(type)
|
156
|
+
offsets << data[type]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
offsets
|
160
|
+
end
|
161
|
+
|
162
|
+
protected
|
163
|
+
|
164
|
+
def self.proccessData(data)
|
165
|
+
data.each do |entry|
|
166
|
+
entry['From'] = DateTime.parse(entry['From']) if entry['From']
|
167
|
+
entry['To'] = DateTime.parse(entry['To']) if entry['To']
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|