1d87fa64b5ada4105efaff4b40bc5434fcf5d7fc
1 # The TimeZone class serves as a wrapper around TZInfo::Timezone instances. It allows us to do the following:
3 # * Limit the set of zones provided by TZInfo to a meaningful subset of 142 zones.
4 # * Retrieve and display zones with a friendlier name (e.g., "Eastern Time (US & Canada)" instead of "America/New_York").
5 # * Lazily load TZInfo::Timezone instances only when they're needed.
6 # * Create ActiveSupport::TimeWithZone instances via TimeZone's +local+, +parse+, +at+ and +now+ methods.
8 # If you set <tt>config.time_zone</tt> in the Rails Initializer, you can access this TimeZone object via <tt>Time.zone</tt>:
11 # Rails::Initializer.run do |config|
12 # config.time_zone = "Eastern Time (US & Canada)"
15 # Time.zone # => #<TimeZone:0x514834...>
16 # Time.zone.name # => "Eastern Time (US & Canada)"
17 # Time.zone.now # => Sun, 18 May 2008 14:30:44 EDT -04:00
19 # The version of TZInfo bundled with Active Support only includes the definitions necessary to support the zones
20 # defined by the TimeZone class. If you need to use zones that aren't defined by TimeZone, you'll need to install the TZInfo gem
21 # (if a recent version of the gem is installed locally, this will be used instead of the bundled version.)
24 unless const_defined
?(:MAPPING)
25 # Keys are Rails TimeZone names, values are TZInfo identifiers
27 "International Date Line West" => "Pacific/Midway",
28 "Midway Island" => "Pacific/Midway",
29 "Samoa" => "Pacific/Pago_Pago",
30 "Hawaii" => "Pacific/Honolulu",
31 "Alaska" => "America/Juneau",
32 "Pacific Time (US & Canada)" => "America/Los_Angeles",
33 "Tijuana" => "America/Tijuana",
34 "Mountain Time (US & Canada)" => "America/Denver",
35 "Arizona" => "America/Phoenix",
36 "Chihuahua" => "America/Chihuahua",
37 "Mazatlan" => "America/Mazatlan",
38 "Central Time (US & Canada)" => "America/Chicago",
39 "Saskatchewan" => "America/Regina",
40 "Guadalajara" => "America/Mexico_City",
41 "Mexico City" => "America/Mexico_City",
42 "Monterrey" => "America/Monterrey",
43 "Central America" => "America/Guatemala",
44 "Eastern Time (US & Canada)" => "America/New_York",
45 "Indiana (East)" => "America/Indiana/Indianapolis",
46 "Bogota" => "America/Bogota",
47 "Lima" => "America/Lima",
48 "Quito" => "America/Lima",
49 "Atlantic Time (Canada)" => "America/Halifax",
50 "Caracas" => "America/Caracas",
51 "La Paz" => "America/La_Paz",
52 "Santiago" => "America/Santiago",
53 "Newfoundland" => "America/St_Johns",
54 "Brasilia" => "America/Sao_Paulo",
55 "Buenos Aires" => "America/Argentina/Buenos_Aires",
56 "Georgetown" => "America/Argentina/San_Juan",
57 "Greenland" => "America/Godthab",
58 "Mid-Atlantic" => "Atlantic/South_Georgia",
59 "Azores" => "Atlantic/Azores",
60 "Cape Verde Is." => "Atlantic/Cape_Verde",
61 "Dublin" => "Europe/Dublin",
62 "Edinburgh" => "Europe/Dublin",
63 "Lisbon" => "Europe/Lisbon",
64 "London" => "Europe/London",
65 "Casablanca" => "Africa/Casablanca",
66 "Monrovia" => "Africa/Monrovia",
68 "Belgrade" => "Europe/Belgrade",
69 "Bratislava" => "Europe/Bratislava",
70 "Budapest" => "Europe/Budapest",
71 "Ljubljana" => "Europe/Ljubljana",
72 "Prague" => "Europe/Prague",
73 "Sarajevo" => "Europe/Sarajevo",
74 "Skopje" => "Europe/Skopje",
75 "Warsaw" => "Europe/Warsaw",
76 "Zagreb" => "Europe/Zagreb",
77 "Brussels" => "Europe/Brussels",
78 "Copenhagen" => "Europe/Copenhagen",
79 "Madrid" => "Europe/Madrid",
80 "Paris" => "Europe/Paris",
81 "Amsterdam" => "Europe/Amsterdam",
82 "Berlin" => "Europe/Berlin",
83 "Bern" => "Europe/Berlin",
84 "Rome" => "Europe/Rome",
85 "Stockholm" => "Europe/Stockholm",
86 "Vienna" => "Europe/Vienna",
87 "West Central Africa" => "Africa/Algiers",
88 "Bucharest" => "Europe/Bucharest",
89 "Cairo" => "Africa/Cairo",
90 "Helsinki" => "Europe/Helsinki",
91 "Kyev" => "Europe/Kiev",
92 "Riga" => "Europe/Riga",
93 "Sofia" => "Europe/Sofia",
94 "Tallinn" => "Europe/Tallinn",
95 "Vilnius" => "Europe/Vilnius",
96 "Athens" => "Europe/Athens",
97 "Istanbul" => "Europe/Istanbul",
98 "Minsk" => "Europe/Minsk",
99 "Jerusalem" => "Asia/Jerusalem",
100 "Harare" => "Africa/Harare",
101 "Pretoria" => "Africa/Johannesburg",
102 "Moscow" => "Europe/Moscow",
103 "St. Petersburg" => "Europe/Moscow",
104 "Volgograd" => "Europe/Moscow",
105 "Kuwait" => "Asia/Kuwait",
106 "Riyadh" => "Asia/Riyadh",
107 "Nairobi" => "Africa/Nairobi",
108 "Baghdad" => "Asia/Baghdad",
109 "Tehran" => "Asia/Tehran",
110 "Abu Dhabi" => "Asia/Muscat",
111 "Muscat" => "Asia/Muscat",
112 "Baku" => "Asia/Baku",
113 "Tbilisi" => "Asia/Tbilisi",
114 "Yerevan" => "Asia/Yerevan",
115 "Kabul" => "Asia/Kabul",
116 "Ekaterinburg" => "Asia/Yekaterinburg",
117 "Islamabad" => "Asia/Karachi",
118 "Karachi" => "Asia/Karachi",
119 "Tashkent" => "Asia/Tashkent",
120 "Chennai" => "Asia/Kolkata",
121 "Kolkata" => "Asia/Kolkata",
122 "Mumbai" => "Asia/Kolkata",
123 "New Delhi" => "Asia/Kolkata",
124 "Kathmandu" => "Asia/Katmandu",
125 "Astana" => "Asia/Dhaka",
126 "Dhaka" => "Asia/Dhaka",
127 "Sri Jayawardenepura" => "Asia/Colombo",
128 "Almaty" => "Asia/Almaty",
129 "Novosibirsk" => "Asia/Novosibirsk",
130 "Rangoon" => "Asia/Rangoon",
131 "Bangkok" => "Asia/Bangkok",
132 "Hanoi" => "Asia/Bangkok",
133 "Jakarta" => "Asia/Jakarta",
134 "Krasnoyarsk" => "Asia/Krasnoyarsk",
135 "Beijing" => "Asia/Shanghai",
136 "Chongqing" => "Asia/Chongqing",
137 "Hong Kong" => "Asia/Hong_Kong",
138 "Urumqi" => "Asia/Urumqi",
139 "Kuala Lumpur" => "Asia/Kuala_Lumpur",
140 "Singapore" => "Asia/Singapore",
141 "Taipei" => "Asia/Taipei",
142 "Perth" => "Australia/Perth",
143 "Irkutsk" => "Asia/Irkutsk",
144 "Ulaan Bataar" => "Asia/Ulaanbaatar",
145 "Seoul" => "Asia/Seoul",
146 "Osaka" => "Asia/Tokyo",
147 "Sapporo" => "Asia/Tokyo",
148 "Tokyo" => "Asia/Tokyo",
149 "Yakutsk" => "Asia/Yakutsk",
150 "Darwin" => "Australia/Darwin",
151 "Adelaide" => "Australia/Adelaide",
152 "Canberra" => "Australia/Melbourne",
153 "Melbourne" => "Australia/Melbourne",
154 "Sydney" => "Australia/Sydney",
155 "Brisbane" => "Australia/Brisbane",
156 "Hobart" => "Australia/Hobart",
157 "Vladivostok" => "Asia/Vladivostok",
158 "Guam" => "Pacific/Guam",
159 "Port Moresby" => "Pacific/Port_Moresby",
160 "Magadan" => "Asia/Magadan",
161 "Solomon Is." => "Asia/Magadan",
162 "New Caledonia" => "Pacific/Noumea",
163 "Fiji" => "Pacific/Fiji",
164 "Kamchatka" => "Asia/Kamchatka",
165 "Marshall Is." => "Pacific/Majuro",
166 "Auckland" => "Pacific/Auckland",
167 "Wellington" => "Pacific/Auckland",
168 "Nuku'alofa" => "Pacific/Tongatapu"
169 }.each
{ |name
, zone
| name
.freeze
; zone
.freeze
}
176 # Create a new TimeZone object with the given name and offset. The
177 # offset is the number of seconds that this time zone is offset from UTC
178 # (GMT). Seconds were chosen as the offset unit because that is the unit that
179 # Ruby uses to represent time zone offsets (see Time#utc_offset).
180 def initialize(name
, utc_offset
, tzinfo
= nil)
182 @utc_offset = utc_offset
187 @utc_offset ||= tzinfo
.current_period
.utc_offset
190 # Returns the offset of this time zone as a formatted string, of the
192 def formatted_offset(colon
=true, alternate_utc_string
= nil)
193 utc_offset
== 0 && alternate_utc_string
|| utc_offset
.to_utc_offset_s(colon
)
196 # Compare this time zone to the parameter. The two are comapred first on
197 # their offsets, and then by name.
199 result
= (utc_offset
<=> zone
.utc_offset
)
200 result
= (name
<=> zone
.name
) if result
== 0
204 # Compare #name and TZInfo identifier to a supplied regexp, returning true
205 # if a match is found.
207 return true if name
=~ re
|| MAPPING
[name
] =~ re
210 # Returns a textual representation of this time zone.
212 "(GMT#{formatted_offset}) #{name}"
215 # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values. Example:
217 # Time.zone = "Hawaii" # => "Hawaii"
218 # Time.zone.local(2007, 2, 1, 15, 30, 45) # => Thu, 01 Feb 2007 15:30:45 HST -10:00
220 time
= Time
.utc_time(*args
)
221 ActiveSupport
::TimeWithZone.new(nil, self, time
)
224 # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from number of seconds since the Unix epoch. Example:
226 # Time.zone = "Hawaii" # => "Hawaii"
227 # Time.utc(2000).to_f # => 946684800.0
228 # Time.zone.at(946684800.0) # => Fri, 31 Dec 1999 14:00:00 HST -10:00
230 utc
= Time
.at(secs
).utc
rescue DateTime
.civil(1970).since(secs
)
231 utc
.in_time_zone(self)
234 # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string. Example:
236 # Time.zone = "Hawaii" # => "Hawaii"
237 # Time.zone.parse('1999-12-31 14:00:00') # => Fri, 31 Dec 1999 14:00:00 HST -10:00
239 # If upper components are missing from the string, they are supplied from TimeZone#now:
241 # Time.zone.now # => Fri, 31 Dec 1999 14:00:00 HST -10:00
242 # Time.zone.parse('22:30:00') # => Fri, 31 Dec 1999 22:30:00 HST -10:00
243 def parse(str
, now
=now
)
244 date_parts
= Date
._parse(str
)
245 return if date_parts
.blank
?
246 time
= Time
.parse(str
, now
) rescue DateTime
.parse(str
)
247 if date_parts
[:offset].nil?
248 ActiveSupport
::TimeWithZone.new(nil, self, time
)
250 time
.in_time_zone(self)
254 # Returns an ActiveSupport::TimeWithZone instance representing the current time
255 # in the time zone represented by +self+. Example:
257 # Time.zone = 'Hawaii' # => "Hawaii"
258 # Time.zone.now # => Wed, 23 Jan 2008 20:24:27 HST -10:00
260 Time
.now
.utc
.in_time_zone(self)
263 # Return the current date in this time zone.
268 # Adjust the given time to the simultaneous time in the time zone represented by +self+. Returns a
269 # Time.utc() instance -- if you want an ActiveSupport::TimeWithZone instance, use Time#in_time_zone() instead.
270 def utc_to_local(time
)
271 tzinfo
.utc_to_local(time
)
274 # Adjust the given time to the simultaneous time in UTC. Returns a Time.utc() instance.
275 def local_to_utc(time
, dst
=true)
276 tzinfo
.local_to_utc(time
, dst
)
279 # Available so that TimeZone instances respond like TZInfo::Timezone instances
280 def period_for_utc(time
)
281 tzinfo
.period_for_utc(time
)
284 # Available so that TimeZone instances respond like TZInfo::Timezone instances
285 def period_for_local(time
, dst
=true)
286 tzinfo
.period_for_local(time
, dst
)
289 # TODO: Preload instead of lazy load for thread safety
291 @tzinfo ||= TZInfo
::Timezone.get(MAPPING
[name
])
294 unless const_defined
?(:ZONES)
297 [[-39_600, "International Date Line West", "Midway Island", "Samoa" ],
298 [-36_000, "Hawaii" ],
299 [-32_400, "Alaska" ],
300 [-28_800, "Pacific Time (US & Canada)", "Tijuana" ],
301 [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan",
303 [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara",
304 "Mexico City", "Monterrey", "Central America" ],
305 [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota",
307 [-16_200, "Caracas" ],
308 [-14_400, "Atlantic Time (Canada)", "La Paz", "Santiago" ],
309 [-12_600, "Newfoundland" ],
310 [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ],
311 [ -7_200, "Mid-Atlantic" ],
312 [ -3_600, "Azores", "Cape Verde Is." ],
313 [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca",
315 [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague",
316 "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels",
317 "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin",
318 "Bern", "Rome", "Stockholm", "Vienna",
319 "West Central Africa" ],
320 [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia",
321 "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk",
322 "Jerusalem", "Harare", "Pretoria" ],
323 [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh",
324 "Nairobi", "Baghdad" ],
325 [ 12_600, "Tehran" ],
326 [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ],
328 [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ],
329 [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi", "Sri Jayawardenepura" ],
330 [ 20_700, "Kathmandu" ],
331 [ 21_600, "Astana", "Dhaka", "Almaty",
333 [ 23_400, "Rangoon" ],
334 [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ],
335 [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi",
336 "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk",
338 [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ],
339 [ 34_200, "Darwin", "Adelaide" ],
340 [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart",
341 "Vladivostok", "Guam", "Port Moresby" ],
342 [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ],
343 [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland",
345 [ 46_800, "Nuku'alofa" ]].
346 each
do |offset
, *places
|
347 places
.each
do |place
|
349 zone
= new(place
, offset
)
351 ZONES_MAP
[place
] = zone
358 US_ZONES
= ZONES
.find_all
{ |z
| z
.name
=~
/US|Arizona|Indiana|Hawaii|Alaska/ }
363 alias_method
:create, :new
365 # Return a TimeZone instance with the given name, or +nil+ if no
366 # such TimeZone instance exists. (This exists to support the use of
367 # this class with the +composed_of+ macro.)
372 # Return an array of all TimeZone objects. There are multiple
373 # TimeZone objects per time zone, in many cases, to make it easier
374 # for users to find their own time zone.
379 # Locate a specific time zone object. If the argument is a string, it
380 # is interpreted to mean the name of the timezone to locate. If it is a
381 # numeric value it is either the hour offset, or the second offset, of the
382 # timezone to find. (The first one with that offset will be returned.)
383 # Returns +nil+ if no such time zone is known to the system.
388 when Numeric
, ActiveSupport
::Duration
389 arg
*= 3600 if arg
.abs
<= 13
390 all
.find
{ |z
| z
.utc_offset
== arg
.to_i
}
392 raise ArgumentError
, "invalid argument to TimeZone[]: #{arg.inspect}"
396 # A convenience method for returning a collection of TimeZone objects
397 # for time zones in the USA.