1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
|
# TZInfo - Ruby Time Zone Library
[](https://rubygems.org/gems/tzinfo) [](https://github.com/tzinfo/tzinfo/actions?query=workflow%3ATests+branch%3Amaster+event%3Apush)
[TZInfo](https://tzinfo.github.io) is a Ruby library that provides access to
time zone data and allows times to be converted using time zone rules.
## Data Sources
TZInfo requires a source of time zone data. There are two options:
1. A zoneinfo directory containing timezone definition files. These files are
generated from the [IANA Time Zone Database](https://www.iana.org/time-zones)
using the `zic` utility. Most Unix-like systems include a zoneinfo directory.
2. The TZInfo::Data library (the tzinfo-data gem). TZInfo::Data contains a set
of Ruby modules that are also generated from the IANA Time Zone Database.
By default, TZInfo will attempt to use TZInfo::Data. If TZInfo::Data is not
available (i.e. if `require 'tzinfo/data'` fails), then TZInfo will search for a
zoneinfo directory instead (using the search path specified by
`TZInfo::ZoneinfoDataSource::DEFAULT_SEARCH_PATH`).
If no data source can be found, a `TZInfo::DataSourceNotFound` exception will be
raised when TZInfo is used. Further information is available
[in the wiki](https://tzinfo.github.io/datasourcenotfound) to help resolve
`TZInfo::DataSourceNotFound` errors.
The default data source selection can be overridden by calling
`TZInfo::DataSource.set`.
Custom data sources can also be used. See the `TZInfo::DataSource.set`
documentation for further details.
## Installation
The TZInfo gem can be installed by running `gem install tzinfo` or by adding
`gem 'tzinfo'` to your `Gemfile` and running `bundle install`.
To use the Ruby modules as the data source, TZInfo::Data will also need to be
installed by running `gem install tzinfo-data` or by adding `gem 'tzinfo-data'`
to your `Gemfile`.
## IANA Time Zone Database
The data returned and used by TZInfo is sourced from the
[IANA Time Zone Database](http://www.iana.org/time-zones). The
[Theory and pragmatics of the tz code and data](https://data.iana.org/time-zones/theory.html)
document gives details of how the data is organized and managed.
## Example Usage
To use TZInfo, it must first be required with:
```ruby
require 'tzinfo'
```
The `TZInfo::Timezone` class provides access to time zone data and methods for
converting times.
The `all_identifiers` method returns a list of valid time zone identifiers:
```ruby
identifiers = TZInfo::Timezone.all_identifiers
# => ["Africa/Adibdjan", "Africa/Accra", ..., "Zulu"]
```
A `TZInfo::Timezone` instance representing an individual time zone can be
obtained with `TZInfo::Timezone.get`:
```ruby
tz = TZInfo::Timezone.get('America/New_York')
# => #<TZInfo::DataTimezone: America/New_York>
```
A time can be converted to the local time of the time zone with `to_local`:
```ruby
tz.to_local(Time.utc(2018, 2, 1, 12, 30, 0))
# => 2018-02-01 07:30:00 -0500
tz.to_local(Time.utc(2018, 7, 1, 12, 30, 0))
# => 2018-07-01 08:30:00 -0400
tz.to_local(Time.new(2018, 7, 1, 13, 30, 0, '+01:00'))
# => 2018-07-01 08:30:00 -0400
```
Local times with the appropriate offset for the time zone can be constructed
with `local_time`:
```ruby
tz.local_time(2018, 2, 1, 7, 30, 0)
# => 2018-02-01 07:30:00 -0500
tz.local_time(2018, 7, 1, 8, 30, 0)
# => 2018-07-01 08:30:00 -0400
```
Local times can be converted to UTC by using `local_time` and calling `utc` on
the result:
```ruby
tz.local_time(2018, 2, 1, 7, 30, 0).utc
# => 2018-02-01 12:30:00 UTC
tz.local_time(2018, 7, 1, 8, 30, 0).utc
# => 2018-07-01 12:30:00 UTC
```
The `local_to_utc` method can also be used to convert a time object to UTC. The
offset of the time is ignored - it is treated as if it were a local time for the
time zone:
```ruby
tz.local_to_utc(Time.utc(2018, 2, 1, 7, 30, 0))
# => 2018-02-01 12:30:00 UTC
tz.local_to_utc(Time.new(2018, 2, 1, 7, 30, 0, '+01:00'))
# => 2018-02-01 12:30:00 UTC
```
Information about the time zone can be obtained from returned local times:
```ruby
local_time = tz.to_local(Time.utc(2018, 2, 1, 12, 30, 0))
local_time.utc_offset # => -18000
local_time.dst? # => false
local_time.zone # => "EST"
local_time = tz.to_local(Time.utc(2018, 7, 1, 12, 30, 0))
local_time.utc_offset # => -14400
local_time.dst? # => true
local_time.zone # => "EDT"
```
Time zone information can be included when formatting times with `strftime`
using the `%z` and `%Z` directives:
```ruby
tz.to_local(Time.utc(2018, 2, 1, 12, 30, 0)).strftime('%Y-%m-%d %H:%M:%S %z %Z')
# => "2018-02-01 07:30:00 -0500 EST"
tz.to_local(Time.utc(2018, 7, 1, 12, 30, 0)).strftime('%Y-%m-%d %H:%M:%S %z %Z')
# => "2018-07-01 08:30:00 -0400 EDT"
```
The `period_for` method can be used to obtain information about the observed
time zone information at a particular time as a `TZInfo::TimezonePeriod` object:
```ruby
period = tz.period_for(Time.utc(2018, 7, 1, 12, 30, 0))
period.base_utc_offset # => -18000
period.std_offset # => 3600
period.observed_utc_offset # => -14400
period.abbreviation # => "EDT"
period.dst? # => true
period.local_starts_at.to_time # => 2018-03-11 03:00:00 -0400
period.local_ends_at.to_time # => 2018-11-04 02:00:00 -0400
```
A list of transitions between periods where different rules are observed can be
obtained with the `transitions_up_to` method. The result is returned as an
`Array` of `TZInfo::TimezoneTransition` objects:
```ruby
transitions = tz.transitions_up_to(Time.utc(2019, 1, 1), Time.utc(2017, 1, 1))
transitions.map do |t|
[t.local_end_at.to_time, t.offset.observed_utc_offset, t.offset.abbreviation]
end
# => [[2017-03-12 02:00:00 -0500, -14400, "EDT"],
# [2017-11-05 02:00:00 -0400, -18000, "EST"],
# [2018-03-11 02:00:00 -0500, -14400, "EDT"],
# [2018-11-04 02:00:00 -0400, -18000, "EST"]]
```
A list of the unique offsets used by a time zone can be obtained with the
`offsets_up_to` method. The result is returned as an `Array` of
`TZInfo::TimezoneOffset` objects:
```ruby
offsets = tz.offsets_up_to(Time.utc(2019, 1, 1))
offsets.map {|o| [o.observed_utc_offset, o.abbreviation] }
# => [[-17762, "LMT"],
# [-18000, "EST"],
# [-14400, "EDT"],
# [-14400, "EWT"],
# [-14400, "EPT"]]
```
All `TZInfo::Timezone` methods that accept a time as a parameter can be used
with either instances of `Time`, `DateTime` or `TZInfo::Timestamp`. Arbitrary
`Time`-like objects that respond to both `to_i` and `subsec` and optionally
`utc_offset` will be treated as if they are instances of `Time`.
`TZInfo::Timezone` methods that both accept and return times will return an
object with a type matching that of the parameter (actually a
`TZInfo::TimeWithOffset`, `TZInfo::DateTimeWithOffset` or
`TZInfo::TimestampWithOffset` subclass when returning a local time):
```ruby
tz.to_local(Time.utc(2018, 7, 1, 12, 30, 0))
# => 2018-07-01 08:30:00 -0400
tz.to_local(DateTime.new(2018, 7, 1, 12, 30, 0))
# => #<TZInfo::DateTimeWithOffset: 2018-07-01T08:30:00-04:00 ((2458301j,45000s,0n),-14400s,2299161j)>
tz.to_local(TZInfo::Timestamp.create(2018, 7, 1, 12, 30, 0, 0, :utc))
# => #<TZInfo::TimestampWithOffset: @value=1530448200, @sub_second=0, @utc_offset=-14400, @utc=false>
```
In addition to `local_time`, which returns `Time` instances, the
`local_datetime` and `local_timestamp` methods can be used to construct local
`DateTime` and `TZInfo::Timestamp` instances with the appropriate offset:
```ruby
tz.local_time(2018, 2, 1, 7, 30, 0)
# => 2018-02-01 07:30:00 -0500
tz.local_datetime(2018, 2, 1, 7, 30, 0)
# => #<TZInfo::DateTimeWithOffset: 2018-02-01T07:30:00-05:00 ((2458151j,45000s,0n),-18000s,2299161j)>
tz.local_timestamp(2018, 2, 1, 7, 30, 0)
# => #<TZInfo::TimestampWithOffset: @value=1517488200, @sub_second=0, @utc_offset=-18000, @utc=false>
```
The `local_to_utc`, `local_time`, `local_datetime` and `local_timestamp` methods
may raise a `TZInfo::PeriodNotFound` or a `TZInfo::AmbiguousTime` exception.
`TZInfo::PeriodNotFound` signals that there is no equivalent UTC time (for
example, during the transition from standard time to daylight savings time when
the clocks are moved forward and an hour is skipped). `TZInfo::AmbiguousTime`
signals that there is more than one equivalent UTC time (for example, during the
transition from daylight savings time to standard time where the clocks are
moved back and an hour is repeated):
```ruby
tz.local_time(2018, 3, 11, 2, 30, 0, 0)
# raises TZInfo::PeriodNotFound (2018-03-11 02:30:00 is an invalid local time.)
tz.local_time(2018, 11, 4, 1, 30, 0, 0)
# raises TZInfo::AmbiguousTime (2018-11-04 01:30:00 is an ambiguous local time.)
```
`TZInfo::PeriodNotFound` exceptions can only be resolved by adjusting the time,
for example, by advancing an hour:
```ruby
tz.local_time(2018, 3, 11, 3, 30, 0, 0)
# => 2018-03-11 03:30:00 -0400
```
`TZInfo::AmbiguousTime` exceptions can be resolved by setting the `dst`
parameter and/or specifying a block to choose one of the interpretations:
```ruby
tz.local_time(2018, 11, 4, 1, 30, 0, 0, true)
# => 2018-11-04 01:30:00 -0400
tz.local_time(2018, 11, 4, 1, 30, 0, 0, false)
# => 2018-11-04 01:30:00 -0500
tz.local_time(2018, 11, 4, 1, 30, 0, 0) {|p| p.first }
# => 2018-11-04 01:30:00 -0400
tz.local_time(2018, 11, 4, 1, 30, 0, 0) {|p| p.last }
# => 2018-11-04 01:30:00 -0500
```
The default value of the `dst` parameter can also be set globally:
```ruby
TZInfo::Timezone.default_dst = true
tz.local_time(2018, 11, 4, 1, 30, 0, 0)
# => 2018-11-04 01:30:00 -0400
TZInfo::Timezone.default_dst = false
tz.local_time(2018, 11, 4, 1, 30, 0, 0)
# => 2018-11-04 01:30:00 -0500
```
TZInfo also provides information about
[ISO 3166-1](https://www.iso.org/iso-3166-country-codes.html) countries and
their associated time zones via the `TZInfo::Country` class.
A list of valid ISO 3166-1 (alpha-2) country codes can be obtained by calling
`TZInfo::Country.all_codes`:
```ruby
TZInfo::Country.all_codes
# => ["AD", "AE", ..., "ZW"]
```
A `TZInfo::Country` instance representing an individual time zone can be
obtained with `TZInfo::Country.get`:
```ruby
c = TZInfo::Country.get('US')
# => #<TZInfo::Country: US>
c.name
# => "United States"
```
The `zone_identifiers` method returns a list of the time zone identifiers used
in a country:
```ruby
c.zone_identifiers
# => ["America/New_York", "America/Detroit", ..., "Pacific/Honolulu"]
```
The `zone_info` method returns further information about the time zones used in
a country as an `Array` of `TZInfo::CountryTimezone` instances:
```ruby
zi = c.zone_info.first
zi.identifier # => "America/New_York"
zi.latitude.to_f.round(5) # => 40.71417
zi.longitude.to_f.round(5) # => -74.00639
zi.description # => "Eastern (most areas)"
```
The `zones` method returns an `Array` of `TZInfo::Timezone` instances for a
country. A `TZInfo::Timezone` instance can be obtained from a
`TZInfo::CountryTimezone` using the `timezone` method:
```ruby
zi.timezone.to_local(Time.utc(2018, 2, 1, 12, 30, 0))
# => 2018-02-01 07:30:00 -0500
```
For further detail, please refer to the API documentation for the
`TZInfo::Timezone` and `TZInfo::Country` classes.
## Time Zone Selection
The Time Zone Database maintainers recommend that time zone identifiers are not
made visible to end-users (see [Names of
timezones](https://data.iana.org/time-zones/theory.html#naming)).
Instead of displaying a list of time zone identifiers, time zones can be
selected by the user's country. Call `TZInfo::Country.all` to obtain a list of
`TZInfo::Country` objects, each with a unique `code` and a `name` that can be
used for display purposes.
Most countries have a single time zone. When choosing such a country, the time
zone can be inferred and selected automatically.
```ruby
croatia = TZInfo::Country.get('HR')
# => #<TZInfo::Country: HR>
croatia.zone_info.length
# => 1
croatia.zone_info[0].identifier
# => "Europe/Belgrade"
```
Some countries have multiple time zones. The `zone_info` method can be used
to obtain a list of user-friendly descriptions of the available options:
```ruby
australia = TZInfo::Country.get('AU')
# => #<TZInfo::Country: AU>
australia.zone_info.length
# => 13
australia.zone_info.map {|i| [i.identifier, i.description] }
# => [["Australia/Lord_Howe", "Lord Howe Island"],
# ["Antarctica/Macquarie", "Macquarie Island"],
# ...
# ["Australia/Eucla", "Western Australia (Eucla)"]]
```
Please note that country information available through TZInfo is intended as an
aid to help users select a time zone data appropriate for their practical needs.
It is not intended to take or endorse any position on legal or territorial
claims.
## Compatibility
TZInfo v2.0.0 requires a minimum of Ruby MRI 1.9.3 or JRuby 1.7 (in 1.9 mode or
later).
## Thread-Safety
The `TZInfo::Country` and `TZInfo::Timezone` classes are thread-safe. It is safe
to use class and instance methods of `TZInfo::Country` and `TZInfo::Timezone` in
concurrently executing threads. Instances of both classes can be shared across
thread boundaries.
## Documentation
API documentation for TZInfo is available on
[RubyDoc.info](https://www.rubydoc.info/gems/tzinfo/).
## License
TZInfo is released under the MIT license, see LICENSE for details.
## Source Code
Source code for TZInfo is available on
[GitHub](https://github.com/tzinfo/tzinfo).
## Issue Tracker
Please post any bugs, issues, feature requests or questions about TZInfo to the
[GitHub issue tracker](https://github.com/tzinfo/tzinfo/issues).
Issues with the underlying time zone data should be raised on the
[Time Zone Database Discussion mailing list](https://mm.icann.org/mailman/listinfo/tz).
|