Vendor dependencies

This commit is contained in:
2026-08-01 16:11:49 +03:00
parent 7f139a0241
commit 6b5e7f0f8b
29706 changed files with 9575646 additions and 0 deletions
@@ -0,0 +1 @@
{"$comment":"This file only protects against accidental modifications. It is not a security mechanism and does not protect against malicious changes.","files":{".cargo_vcs_info.json":"52cadcdad2870992d62876f78690e496652195d522312e661f1e4fa70b7b186b","Cargo.toml":"9f99dd8eba1e6d99f25e0c2fcbd1b5a100589104f0b6e1f2ed01de659ea11421","Cargo.toml.orig":"d07e6d23afda9fb723c586108d030f69ce39e6f13d6dfb5810ba9966713264f8","LICENSE":"1e881ecf2862d01e6e5bc2b861e46886d2a6fb01499c0c508a209a7271b13cf2","README.md":"d3cd7c05bf07c6a04630341c7364f4173e7f30dd93c053c47f59e284a3707d5b","build.rs":"660da59ddcf7302be92a34055b46db0146cab23ee26d88029179d468ab31035d","src/binary_search.rs":"dfeccd38e276d323b0b73f920baa2f19c857d137c4fb0b5e12a172e17df590ac","src/directory.rs":"00de8b05a08bd3f3965a2da5b6e50ce42b9f3264c41868f0c7c3ec90d22aabb4","src/lib.rs":"cd91767967ebeaec309e2148819cb934fe06f65c77c7600051d416685b04f43a","src/serde.rs":"6a671a50107fa0a7791e004672b92704443f9b508d81aac54a1c2f688c4c4249","src/timezone_impl.rs":"9544bf313223737cbbe58861aff84341dd72e2e8a92904170b5884ab21001341","src/timezones.rs":"7a0fc42414541eb63d462e8fb654e6bb2fa382e76e20199e0060f68e9958fabd","tests/numberphile.rs":"68ab1599b163092e209de1264e8693b65ccba54c35a3329170ffcadcd14a2764","tz/LICENSE":"0613408568889f5739e5ae252b722a2659c02002839ad970a63dc5e9174b27cf","tz/NEWS":"f7eaa2f39750fd4e1afb72e3421395836f901d93cb13963223414ea5367ec39c","tz/africa":"d3ca90ea6e5171f2125eb81c53f4dc62d52c1c9189fd020774fdfff9b0e21c40","tz/antarctica":"3226b844e9b7a35cedff813d20aba5fc07fcd6f0eea268e998f409bcb813868a","tz/asia":"5ee9bf22ce72cbd3da504be8a7332e87d9afab6b69a657121d885d91ef000d92","tz/australasia":"0d9b025e15e375c456cff94f7163cce7d308929baab3ab2b6037facd24d42359","tz/backward":"b9514f28331955274fb293d0b2922212d62b4426d1adf6dc1b271864abf327cc","tz/etcetera":"cfd38ef4f0f6b0ba138c8e9b3c7d946c7422d490fd214ccf2cd737dc2cb603cb","tz/europe":"cc7ced8b5713eaa780937839764daff17bbe9a226c289b709d1afd80d247e0ef","tz/northamerica":"f1e040f23c69f60e222a6784e9ab27fd5a45daedb3d8814145a7e52e962892ff","tz/southamerica":"a10c7c13a735f657d1238d9832c4ce260b1c740dbae09d9a57fdece8cbe5b901"},"package":"93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb"}
@@ -0,0 +1,6 @@
{
"git": {
"sha1": "6987cd65833504365c9225c8096f14933daa4fa5"
},
"path_in_vcs": "chrono-tz"
}
+98
View File
@@ -0,0 +1,98 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.60"
name = "chrono-tz"
version = "0.9.0"
build = "build.rs"
include = [
"src/*.rs",
"tests/*.rs",
"build.rs",
"LICENSE",
"tz/africa",
"tz/antarctica",
"tz/asia",
"tz/australasia",
"tz/backward",
"tz/etcetera",
"tz/europe",
"tz/northamerica",
"tz/southamerica",
"tz/NEWS",
]
description = "TimeZone implementations for chrono from the IANA database"
documentation = "https://docs.rs/chrono-tz"
readme = "README.md"
keywords = [
"date",
"time",
"timezone",
"zone",
"iana",
]
categories = ["date-and-time"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/chronotope/chrono-tz"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = [
"--cfg",
"docsrs",
]
[dependencies.arbitrary]
version = "1.2"
features = ["derive"]
optional = true
[dependencies.chrono]
version = "0.4.25"
default-features = false
[dependencies.phf]
version = "0.11"
default-features = false
[dependencies.serde]
version = "1.0.99"
optional = true
default-features = false
[dependencies.uncased]
version = "0.9"
optional = true
default-features = false
[dev-dependencies.chrono]
version = "0.4"
features = ["alloc"]
default-features = false
[dev-dependencies.serde_test]
version = "1"
[build-dependencies.chrono-tz-build]
version = "0.3"
[features]
case-insensitive = [
"dep:uncased",
"chrono-tz-build/case-insensitive",
"phf/uncased",
]
default = ["std"]
filter-by-regex = ["chrono-tz-build/filter-by-regex"]
serde = ["dep:serde"]
std = []
+54
View File
@@ -0,0 +1,54 @@
[package]
name = "chrono-tz"
version = "0.9.0"
edition = "2021"
rust-version = "1.60"
build = "build.rs"
description = "TimeZone implementations for chrono from the IANA database"
keywords = ["date", "time", "timezone", "zone", "iana"]
categories = ["date-and-time"]
repository = "https://github.com/chronotope/chrono-tz"
documentation = "https://docs.rs/chrono-tz"
readme = "../README.md"
license = "MIT OR Apache-2.0"
include = [
"src/*.rs",
"tests/*.rs",
"build.rs",
"LICENSE",
"tz/africa",
"tz/antarctica",
"tz/asia",
"tz/australasia",
"tz/backward",
"tz/etcetera",
"tz/europe",
"tz/northamerica",
"tz/southamerica",
"tz/NEWS",
]
[dependencies]
arbitrary = { version = "1.2", optional = true, features = ["derive"] }
chrono = { version = "0.4.25", default-features = false }
serde = { version = "1.0.99", optional = true, default-features = false }
phf = { version = "0.11", default-features = false }
uncased = { version = "0.9", optional = true, default-features = false }
[features]
default = ["std"]
std = []
serde = ["dep:serde"]
filter-by-regex = ["chrono-tz-build/filter-by-regex"]
case-insensitive = ["dep:uncased", "chrono-tz-build/case-insensitive", "phf/uncased"]
[build-dependencies]
chrono-tz-build = { path = "../chrono-tz-build", version = "0.3" }
[dev-dependencies]
serde_test = "1"
chrono = { version = "0.4", default-features = false, features = ["alloc"] }
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
+1
View File
@@ -0,0 +1 @@
../LICENSE
+183
View File
@@ -0,0 +1,183 @@
# Chrono-TZ
`Chrono-TZ` is a library that provides implementors of the
[`TimeZone`][timezone] trait for [`rust-chrono`][chrono]. The
impls are generated by a build script using the [`IANA database`][iana]
and [`parse-zoneinfo`][parse_zoneinfo].
[chrono]: https://github.com/lifthrasiir/rust-chrono
[timezone]: https://lifthrasiir.github.io/rust-chrono/chrono/offset/trait.TimeZone.html
[iana]: http://www.iana.org/time-zones
[parse_zoneinfo]: https://github.com/djzin/parse-zoneinfo
## Documentation
Documentation is hosted on [docs.rs][docsrs]
[docsrs]: https://docs.rs/chrono-tz
## Examples
Create a time in one timezone and convert it to UTC
```rust
use chrono::{TimeZone, Utc};
use chrono_tz::US::Pacific;
let pacific_time = Pacific.ymd(1990, 5, 6).and_hms(12, 30, 45);
let utc_time = pacific_time.with_timezone(&Utc);
assert_eq!(utc_time, Utc.ymd(1990, 5, 6).and_hms(19, 30, 45));
```
Create a naive datetime and convert it to a timezone-aware datetime
```rust
use chrono::{TimeZone, NaiveDate};
use chrono_tz::Africa::Johannesburg;
let naive_dt = NaiveDate::from_ymd(2038, 1, 19).and_hms(3, 14, 08);
let tz_aware = Johannesburg.from_local_datetime(&naive_dt).unwrap();
assert_eq!(tz_aware.to_string(), "2038-01-19 03:14:08 SAST");
```
London and New York change their clocks on different days in March
so only have a 4-hour difference on certain days.
```rust
use chrono::TimeZone;
use chrono_tz::Europe::London;
use chrono_tz::America::New_York;
let london_time = London.ymd(2016, 3, 18).and_hms(3, 0, 0);
let ny_time = london_time.with_timezone(&New_York);
assert_eq!(ny_time, New_York.ymd(2016, 3, 17).and_hms(23, 0, 0));
```
You can get the raw offsets as well if you want to see the standard
UTC offset as well as any special offsets in effect (such as DST)
at a given time. Note that you need to import the `OffsetComponents`
trait.
```rust
use chrono::{Duration, TimeZone};
use chrono_tz::Europe::London;
use chrono_tz::OffsetComponents;
let london_time = London.ymd(2016, 5, 10).and_hms(12, 0, 0);
// London typically has zero offset from UTC, but has a 1h adjustment forward
// when summer time is in effect.
assert_eq!(london_time.offset().base_utc_offset(), Duration::hours(0));
assert_eq!(london_time.offset().dst_offset(), Duration::hours(1));
```
Adding 24 hours across a daylight savings change causes a change
in local time
```rust
use chrono::{TimeZone, Duration};
use chrono_tz::Europe::London;
let dt = London.ymd(2016, 10, 29).and_hms(12, 0, 0);
let later = dt + Duration::hours(24);
assert_eq!(later, London.ymd(2016, 10, 30).and_hms(11, 0, 0));
```
And of course you can always convert a local time to a unix timestamp
```rust
use chrono::TimeZone;
use chrono_tz::Asia::Kolkata;
let dt = Kolkata.ymd(2000, 1, 1).and_hms(0, 0, 0);
let timestamp = dt.timestamp();
assert_eq!(timestamp, 946665000);
```
Pretty-printing a string will use the correct abbreviation for the timezone
```rust
use chrono::TimeZone;
use chrono_tz::Europe::London;
let dt = London.ymd(2016, 5, 10).and_hms(12, 0, 0);
assert_eq!(dt.to_string(), "2016-05-10 12:00:00 BST");
assert_eq!(dt.to_rfc3339(), "2016-05-10T12:00:00+01:00");
```
You can convert a timezone string to a timezone using the FromStr trait
```rust
use chrono::TimeZone;
use chrono_tz::Tz;
use chrono_tz::UTC;
let tz: Tz = "Antarctica/South_Pole".parse().unwrap();
let dt = tz.ymd(2016, 10, 22).and_hms(12, 0, 0);
let utc = dt.with_timezone(&UTC);
assert_eq!(utc.to_string(), "2016-10-21 23:00:00 UTC");
```
## `no_std` Support
To use this library without depending on the Rust standard library, put this
in your `Cargo.toml`:
```toml
[dependencies]
chrono = { version = "0.4", default-features = false }
chrono-tz = { version = "0.5", default-features = false }
```
If you are using this library in an environment with limited program
space, such as a microcontroller, take note that you will also likely
need to enable optimizations and Link Time Optimization:
```toml
[profile.dev]
opt-level = 2
lto = true
[profile.release]
lto = true
```
Otherwise, the additional binary size added by this library may overflow
available program space and trigger a linker error.
## Limiting the Timezone Table to Zones of Interest
`Chrono-tz` by default generates timezones for all entries in the [IANA database][]. If you are
interested in only a few timezones you can use enable the `filter-by-regex` feature and set an
environment variable to select them. The environment variable is called
`CHRONO_TZ_TIMEZONE_FILTER` and is a regular expression. It should be specified in your top-level
build:
```toml
[dependencies]
chrono-tz = { version = "0.6", features = [ "filter-by-regex" ] }
```
```sh
CHRONO_TZ_TIMEZONE_FILTER="(Europe/London|US/.*)" cargo build
```
This can significantly reduce the size of the generated database, depending on how many timezones
you are interested in. Wikipedia has an [article listing the timezone names][wiki-list].
The filtering applied is liberal; if you use a pattern such as "US/.*" then `chrono-tz` will
include all the zones that are linked, such as "America/Denver", not just "US/Mountain".
[IANA database]: http://www.iana.org/time-zones
[wiki-list]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
## Developing
`chrono-tz` uses git submodules, so in order to build locally you will need to
run `git submodule init` and `git submodule update`.
## Future Improvements
- Handle leap seconds
- Handle Julian to Gregorian calendar transitions
- Load tzdata always from latest version
- Dynamic tzdata loading
+3
View File
@@ -0,0 +1,3 @@
fn main() {
chrono_tz_build::main();
}
@@ -0,0 +1,33 @@
use core::cmp::Ordering;
/// An implementation of binary search on indices only
/// that does not require slices to be constructed. Mirrors
/// the semantics of binary_search_by in the standard library.
pub fn binary_search<F>(mut start: usize, mut end: usize, mut f: F) -> Result<usize, usize>
where
F: FnMut(usize) -> Ordering,
{
loop {
let mid = start + (end - start) / 2;
if mid == end {
return Err(start);
}
match f(mid) {
Ordering::Less => start = mid + 1,
Ordering::Greater => end = mid,
Ordering::Equal => return Ok(mid),
}
}
}
#[test]
fn test_binary_search() {
assert_eq!(binary_search(0, 5000, |x| x.cmp(&1337)), Ok(1337));
assert_eq!(binary_search(0, 5000, |x| x.cmp(&9000)), Err(5000));
assert_eq!(binary_search(30, 50, |x| x.cmp(&42)), Ok(42));
assert_eq!(binary_search(300, 500, |x| x.cmp(&42)), Err(300));
assert_eq!(
binary_search(0, 500, |x| if x < 42 { Ordering::Less } else { Ordering::Greater }),
Err(42)
);
}
+5
View File
@@ -0,0 +1,5 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(dead_code)]
include!(concat!(env!("OUT_DIR"), "/directory.rs"));
+415
View File
@@ -0,0 +1,415 @@
//! # Chrono-TZ
//!
//! `Chrono-TZ` is a library that provides implementors of the
//! [`TimeZone`][timezone] trait for [`chrono`][chrono]. The
//! impls are generated by a build script using the [`IANA database`][iana]
//! and [`zoneinfo_parse`][zoneinfo_parse].
//!
//! [chrono]: https://github.com/lifthrasiir/rust-chrono
//! [timezone]: https://lifthrasiir.github.io/rust-chrono/chrono/offset/trait.TimeZone.html
//! [iana]: http://www.iana.org/time-zones
//! [zoneinfo_parse]: https://github.com/rust-datetime/zoneinfo-parse
//!
//! ## Examples
//!
//! Create a time in one timezone and convert it to UTC
//!
//! ```
//! # extern crate chrono;
//! # extern crate chrono_tz;
//! use chrono::{TimeZone, Utc};
//! use chrono_tz::US::Pacific;
//!
//! # fn main() {
//! let pacific_time = Pacific.ymd(1990, 5, 6).and_hms(12, 30, 45);
//! let utc_time = pacific_time.with_timezone(&Utc);
//! assert_eq!(utc_time, Utc.ymd(1990, 5, 6).and_hms(19, 30, 45));
//! # }
//! ```
//!
//! Create a naive datetime and convert it to a timezone-aware datetime
//!
//! ```
//! # extern crate chrono;
//! # extern crate chrono_tz;
//! use chrono::{TimeZone, NaiveDate};
//! use chrono_tz::Africa::Johannesburg;
//!
//! # fn main() {
//! let naive_dt = NaiveDate::from_ymd(2038, 1, 19).and_hms(3, 14, 08);
//! let tz_aware = Johannesburg.from_local_datetime(&naive_dt).unwrap();
//! assert_eq!(tz_aware.to_string(), "2038-01-19 03:14:08 SAST");
//! # }
//! ```
//!
//! London and New York change their clocks on different days in March
//! so only have a 4-hour difference on certain days.
//!
//! ```
//! # extern crate chrono;
//! # extern crate chrono_tz;
//! use chrono::TimeZone;
//! use chrono_tz::Europe::London;
//! use chrono_tz::America::New_York;
//!
//! # fn main() {
//! let london_time = London.ymd(2016, 3, 18).and_hms(3, 0, 0);
//! let ny_time = london_time.with_timezone(&New_York);
//! assert_eq!(ny_time, New_York.ymd(2016, 3, 17).and_hms(23, 0, 0));
//! # }
//! ```
//!
//! Adding 24 hours across a daylight savings change causes a change
//! in local time
//!
//! ```
//! # extern crate chrono;
//! # extern crate chrono_tz;
//! use chrono::{TimeZone, Duration};
//! use chrono_tz::Europe::London;
//!
//! # fn main() {
//! let dt = London.ymd(2016, 10, 29).and_hms(12, 0, 0);
//! let later = dt + Duration::hours(24);
//! assert_eq!(later, London.ymd(2016, 10, 30).and_hms(11, 0, 0));
//! # }
//! ```
//!
//! And of course you can always convert a local time to a unix timestamp
//!
//! ```
//! # extern crate chrono;
//! # extern crate chrono_tz;
//! use chrono::TimeZone;
//! use chrono_tz::Asia::Kolkata;
//!
//! # fn main() {
//! let dt = Kolkata.ymd(2000, 1, 1).and_hms(0, 0, 0);
//! let timestamp = dt.timestamp();
//! assert_eq!(timestamp, 946665000);
//! # }
//! ```
//!
//! Pretty-printing a string will use the correct abbreviation for the timezone
//!
//! ```
//! # extern crate chrono;
//! # extern crate chrono_tz;
//! use chrono::TimeZone;
//! use chrono_tz::Europe::London;
//!
//! # fn main() {
//! let dt = London.ymd(2016, 5, 10).and_hms(12, 0, 0);
//! assert_eq!(dt.to_string(), "2016-05-10 12:00:00 BST");
//! assert_eq!(dt.to_rfc3339(), "2016-05-10T12:00:00+01:00");
//! # }
//! ```
//!
//! You can convert a timezone string to a timezone using the `FromStr` trait
//!
//! ```
//! # extern crate chrono;
//! # extern crate chrono_tz;
//! use chrono::TimeZone;
//! use chrono_tz::Tz;
//! use chrono_tz::UTC;
//!
//! # fn main() {
//! let tz: Tz = "Antarctica/South_Pole".parse().unwrap();
//! let dt = tz.ymd(2016, 10, 22).and_hms(12, 0, 0);
//! let utc = dt.with_timezone(&UTC);
//! assert_eq!(utc.to_string(), "2016-10-21 23:00:00 UTC");
//! # }
//! ```
//!
//! If you need to iterate over all variants you can use the `TZ_VARIANTS` array
//! ```
//! use chrono_tz::{TZ_VARIANTS, Tz};
//! assert!(TZ_VARIANTS.iter().any(|v| *v == Tz::UTC));
//! ```
#![cfg_attr(not(any(feature = "std", test)), no_std)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#[cfg(feature = "serde")]
mod serde;
mod binary_search;
mod directory;
mod timezone_impl;
mod timezones;
pub use crate::directory::*;
pub use crate::timezone_impl::{OffsetComponents, OffsetName};
pub use crate::timezones::ParseError;
pub use crate::timezones::Tz;
pub use crate::timezones::TZ_VARIANTS;
pub use crate::IANA_TZDB_VERSION;
#[cfg(test)]
mod tests {
use super::America::Danmarkshavn;
use super::Asia::Dhaka;
use super::Australia::Adelaide;
use super::Europe::Berlin;
use super::Europe::London;
use super::Europe::Moscow;
use super::Europe::Vilnius;
use super::Europe::Warsaw;
use super::Pacific::Apia;
use super::Pacific::Noumea;
use super::Pacific::Tahiti;
use super::Tz;
use super::IANA_TZDB_VERSION;
use super::US::Eastern;
use super::UTC;
use chrono::{Duration, NaiveDate, TimeZone};
#[test]
fn london_to_berlin() {
let dt = London.with_ymd_and_hms(2016, 10, 8, 17, 0, 0).unwrap();
let converted = dt.with_timezone(&Berlin);
let expected = Berlin.with_ymd_and_hms(2016, 10, 8, 18, 0, 0).unwrap();
assert_eq!(converted, expected);
}
#[test]
fn us_eastern_dst_commutativity() {
let dt = UTC.with_ymd_and_hms(2002, 4, 7, 7, 0, 0).unwrap();
for days in -420..720 {
let dt1 = (dt + Duration::days(days)).with_timezone(&Eastern);
let dt2 = dt.with_timezone(&Eastern) + Duration::days(days);
assert_eq!(dt1, dt2);
}
}
#[test]
fn test_addition_across_dst_boundary() {
use chrono::TimeZone;
let two_hours = Duration::hours(2);
let edt = Eastern.with_ymd_and_hms(2019, 11, 3, 0, 0, 0).unwrap();
let est = edt + two_hours;
assert_eq!(edt.to_string(), "2019-11-03 00:00:00 EDT".to_string());
assert_eq!(est.to_string(), "2019-11-03 01:00:00 EST".to_string());
assert_eq!(est.timestamp(), edt.timestamp() + two_hours.num_seconds());
}
#[test]
fn warsaw_tz_name() {
let dt = UTC.with_ymd_and_hms(1915, 8, 4, 22, 35, 59).unwrap();
assert_eq!(dt.with_timezone(&Warsaw).format("%Z").to_string(), "WMT");
let dt = dt + Duration::seconds(1);
assert_eq!(dt.with_timezone(&Warsaw).format("%Z").to_string(), "CET");
}
#[test]
fn vilnius_utc_offset() {
let dt = UTC.with_ymd_and_hms(1916, 12, 31, 22, 35, 59).unwrap().with_timezone(&Vilnius);
assert_eq!(dt, Vilnius.with_ymd_and_hms(1916, 12, 31, 23, 59, 59).unwrap());
let dt = dt + Duration::seconds(1);
assert_eq!(dt, Vilnius.with_ymd_and_hms(1917, 1, 1, 0, 11, 36).unwrap());
}
#[test]
fn victorian_times() {
let dt = UTC.with_ymd_and_hms(1847, 12, 1, 0, 1, 14).unwrap().with_timezone(&London);
assert_eq!(dt, London.with_ymd_and_hms(1847, 11, 30, 23, 59, 59).unwrap());
let dt = dt + Duration::seconds(1);
assert_eq!(dt, London.with_ymd_and_hms(1847, 12, 1, 0, 1, 15).unwrap());
}
#[test]
fn london_dst() {
let dt = London.with_ymd_and_hms(2016, 3, 10, 5, 0, 0).unwrap();
let later = dt + Duration::days(180);
let expected = London.with_ymd_and_hms(2016, 9, 6, 6, 0, 0).unwrap();
assert_eq!(later, expected);
}
#[test]
fn international_date_line_change() {
let dt = UTC.with_ymd_and_hms(2011, 12, 30, 9, 59, 59).unwrap().with_timezone(&Apia);
assert_eq!(dt, Apia.with_ymd_and_hms(2011, 12, 29, 23, 59, 59).unwrap());
let dt = dt + Duration::seconds(1);
assert_eq!(dt, Apia.with_ymd_and_hms(2011, 12, 31, 0, 0, 0).unwrap());
}
#[test]
fn negative_offset_with_minutes_and_seconds() {
let dt = UTC.with_ymd_and_hms(1900, 1, 1, 12, 0, 0).unwrap().with_timezone(&Danmarkshavn);
assert_eq!(dt, Danmarkshavn.with_ymd_and_hms(1900, 1, 1, 10, 45, 20).unwrap());
}
#[test]
fn monotonicity() {
let mut dt = Noumea.with_ymd_and_hms(1800, 1, 1, 12, 0, 0).unwrap();
for _ in 0..24 * 356 * 400 {
let new = dt + Duration::hours(1);
assert!(new > dt);
assert!(new.with_timezone(&UTC) > dt.with_timezone(&UTC));
dt = new;
}
}
fn test_inverse<T: TimeZone>(tz: T, begin: i32, end: i32) {
for y in begin..end {
for d in 1..366 {
let date = NaiveDate::from_yo_opt(y, d).unwrap();
for h in 0..24 {
for m in 0..60 {
let dt = date.and_hms_opt(h, m, 0).unwrap().and_utc();
let with_tz = dt.with_timezone(&tz);
let utc = with_tz.with_timezone(&UTC);
assert_eq!(dt, utc);
}
}
}
}
}
#[test]
fn inverse_london() {
test_inverse(London, 1989, 1994);
}
#[test]
fn inverse_dhaka() {
test_inverse(Dhaka, 1995, 2000);
}
#[test]
fn inverse_apia() {
test_inverse(Apia, 2011, 2012);
}
#[test]
fn inverse_tahiti() {
test_inverse(Tahiti, 1911, 1914);
}
#[test]
fn string_representation() {
let dt = UTC.with_ymd_and_hms(2000, 9, 1, 12, 30, 15).unwrap().with_timezone(&Adelaide);
assert_eq!(dt.to_string(), "2000-09-01 22:00:15 ACST");
assert_eq!(format!("{:?}", dt), "2000-09-01T22:00:15ACST");
assert_eq!(dt.to_rfc3339(), "2000-09-01T22:00:15+09:30");
assert_eq!(format!("{}", dt), "2000-09-01 22:00:15 ACST");
}
#[test]
fn tahiti() {
let dt = UTC.with_ymd_and_hms(1912, 10, 1, 9, 58, 16).unwrap().with_timezone(&Tahiti);
let before = dt - Duration::hours(1);
assert_eq!(before, Tahiti.with_ymd_and_hms(1912, 9, 30, 23, 0, 0).unwrap());
let after = dt + Duration::hours(1);
assert_eq!(after, Tahiti.with_ymd_and_hms(1912, 10, 1, 0, 58, 16).unwrap());
}
#[test]
fn nonexistent_time() {
assert!(London.with_ymd_and_hms(2016, 3, 27, 1, 30, 0).single().is_none());
}
#[test]
fn nonexistent_time_2() {
assert!(London.with_ymd_and_hms(2016, 3, 27, 1, 0, 0).single().is_none());
}
#[test]
fn time_exists() {
assert!(London.with_ymd_and_hms(2016, 3, 27, 2, 0, 0).single().is_some());
}
#[test]
fn ambiguous_time() {
let ambiguous = London.with_ymd_and_hms(2016, 10, 30, 1, 0, 0);
let earliest_utc =
NaiveDate::from_ymd_opt(2016, 10, 30).unwrap().and_hms_opt(0, 0, 0).unwrap();
assert_eq!(ambiguous.earliest().unwrap(), London.from_utc_datetime(&earliest_utc));
let latest_utc =
NaiveDate::from_ymd_opt(2016, 10, 30).unwrap().and_hms_opt(1, 0, 0).unwrap();
assert_eq!(ambiguous.latest().unwrap(), London.from_utc_datetime(&latest_utc));
}
#[test]
fn ambiguous_time_2() {
let ambiguous = London.with_ymd_and_hms(2016, 10, 30, 1, 30, 0);
let earliest_utc =
NaiveDate::from_ymd_opt(2016, 10, 30).unwrap().and_hms_opt(0, 30, 0).unwrap();
assert_eq!(ambiguous.earliest().unwrap(), London.from_utc_datetime(&earliest_utc));
let latest_utc =
NaiveDate::from_ymd_opt(2016, 10, 30).unwrap().and_hms_opt(1, 30, 0).unwrap();
assert_eq!(ambiguous.latest().unwrap(), London.from_utc_datetime(&latest_utc));
}
#[test]
fn ambiguous_time_3() {
let ambiguous = Moscow.with_ymd_and_hms(2014, 10, 26, 1, 30, 0);
let earliest_utc =
NaiveDate::from_ymd_opt(2014, 10, 25).unwrap().and_hms_opt(21, 30, 0).unwrap();
assert_eq!(
ambiguous.earliest().unwrap().fixed_offset(),
Moscow.from_utc_datetime(&earliest_utc).fixed_offset()
);
let latest_utc =
NaiveDate::from_ymd_opt(2014, 10, 25).unwrap().and_hms_opt(22, 30, 0).unwrap();
assert_eq!(ambiguous.latest().unwrap(), Moscow.from_utc_datetime(&latest_utc));
}
#[test]
fn ambiguous_time_4() {
let ambiguous = Moscow.with_ymd_and_hms(2014, 10, 26, 1, 0, 0);
let earliest_utc =
NaiveDate::from_ymd_opt(2014, 10, 25).unwrap().and_hms_opt(21, 0, 0).unwrap();
assert_eq!(
ambiguous.earliest().unwrap().fixed_offset(),
Moscow.from_utc_datetime(&earliest_utc).fixed_offset()
);
let latest_utc =
NaiveDate::from_ymd_opt(2014, 10, 25).unwrap().and_hms_opt(22, 0, 0).unwrap();
assert_eq!(ambiguous.latest().unwrap(), Moscow.from_utc_datetime(&latest_utc));
}
#[test]
fn unambiguous_time() {
assert!(London.with_ymd_and_hms(2016, 10, 30, 2, 0, 0).single().is_some());
}
#[test]
fn unambiguous_time_2() {
assert!(Moscow.with_ymd_and_hms(2014, 10, 26, 2, 0, 0).single().is_some());
}
#[test]
fn test_get_name() {
assert_eq!(London.name(), "Europe/London");
assert_eq!(Tz::Africa__Abidjan.name(), "Africa/Abidjan");
assert_eq!(Tz::UTC.name(), "UTC");
assert_eq!(Tz::Zulu.name(), "Zulu");
}
#[test]
fn test_display() {
assert_eq!(format!("{}", London), "Europe/London");
assert_eq!(format!("{}", Tz::Africa__Abidjan), "Africa/Abidjan");
assert_eq!(format!("{}", Tz::UTC), "UTC");
assert_eq!(format!("{}", Tz::Zulu), "Zulu");
}
#[test]
fn test_impl_hash() {
#[allow(dead_code)]
#[derive(Hash)]
struct Foo(Tz);
}
#[test]
fn test_iana_tzdb_version() {
// Format should be something like 2023c.
assert_eq!(5, IANA_TZDB_VERSION.len());
let numbers: Vec<&str> = IANA_TZDB_VERSION.matches(char::is_numeric).collect();
assert_eq!(4, numbers.len());
assert!(IANA_TZDB_VERSION.ends_with(|c: char| c.is_ascii_lowercase()));
}
}
+61
View File
@@ -0,0 +1,61 @@
extern crate serde;
use self::serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use core::fmt;
use crate::timezones::Tz;
impl Serialize for Tz {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.name())
}
}
impl<'de> Deserialize<'de> for Tz {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Tz;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "an IANA timezone string")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Tz, E> {
value.parse::<Tz>().map_err(|_| E::custom(SerdeError(value)))
}
}
deserializer.deserialize_str(Visitor)
}
}
struct SerdeError<'a>(&'a str);
impl fmt::Display for SerdeError<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "failed to parse timezone: '{}'", self.0)
}
}
#[cfg(test)]
mod tests {
use crate::timezones::Tz::{self, Etc__UTC, Europe__London, UTC};
use serde_test::{assert_de_tokens_error, assert_tokens, Token};
#[test]
fn serde_ok_both_ways() {
assert_tokens(&Europe__London, &[Token::String("Europe/London")]);
assert_tokens(&Etc__UTC, &[Token::String("Etc/UTC")]);
assert_tokens(&UTC, &[Token::String("UTC")]);
}
#[test]
fn serde_de_error() {
assert_de_tokens_error::<Tz>(
&[Token::Str("Europe/L")],
"failed to parse timezone: 'Europe/L'",
);
}
}
@@ -0,0 +1,370 @@
use core::cmp::Ordering;
use core::fmt::{Debug, Display, Error, Formatter};
use chrono::{
Duration, FixedOffset, LocalResult, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone,
};
use crate::binary_search::binary_search;
use crate::timezones::Tz;
/// Returns [`Tz::UTC`].
impl Default for Tz {
fn default() -> Self {
Tz::UTC
}
}
/// An Offset that applies for a period of time
///
/// For example, [`::US::Eastern`] is composed of at least two
/// `FixedTimespan`s: `EST` and `EDT`, that are variously in effect.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct FixedTimespan {
/// The base offset from UTC; this usually doesn't change unless the government changes something
pub utc_offset: i32,
/// The additional offset from UTC for this timespan; typically for daylight saving time
pub dst_offset: i32,
/// The name of this timezone, for example the difference between `EDT`/`EST`
pub name: &'static str,
}
impl Offset for FixedTimespan {
fn fix(&self) -> FixedOffset {
FixedOffset::east_opt(self.utc_offset + self.dst_offset).unwrap()
}
}
impl Display for FixedTimespan {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
write!(f, "{}", self.name)
}
}
impl Debug for FixedTimespan {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
write!(f, "{}", self.name)
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct TzOffset {
tz: Tz,
offset: FixedTimespan,
}
/// Detailed timezone offset components that expose any special conditions currently in effect.
///
/// This trait breaks down an offset into the standard UTC offset and any special offset
/// in effect (such as DST) at a given time.
///
/// ```
/// # extern crate chrono;
/// # extern crate chrono_tz;
/// use chrono::{Duration, Offset, TimeZone};
/// use chrono_tz::Europe::London;
/// use chrono_tz::OffsetComponents;
///
/// # fn main() {
/// let london_time = London.ymd(2016, 5, 10).and_hms(12, 0, 0);
///
/// // London typically has zero offset from UTC, but has a 1h adjustment forward
/// // when summer time is in effect.
/// let lon_utc_offset = london_time.offset().base_utc_offset();
/// let lon_dst_offset = london_time.offset().dst_offset();
/// let total_offset = lon_utc_offset + lon_dst_offset;
/// assert_eq!(lon_utc_offset, Duration::hours(0));
/// assert_eq!(lon_dst_offset, Duration::hours(1));
///
/// // As a sanity check, make sure that the total offsets added together are equivalent to the
/// // total fixed offset.
/// assert_eq!(total_offset.num_seconds(), london_time.offset().fix().local_minus_utc() as i64);
/// # }
/// ```
pub trait OffsetComponents {
/// The base offset from UTC; this usually doesn't change unless the government changes something
fn base_utc_offset(&self) -> Duration;
/// The additional offset from UTC that is currently in effect; typically for daylight saving time
fn dst_offset(&self) -> Duration;
}
/// Timezone offset name information.
///
/// This trait exposes display names that describe an offset in
/// various situations.
///
/// ```
/// # extern crate chrono;
/// # extern crate chrono_tz;
/// use chrono::{Duration, Offset, TimeZone};
/// use chrono_tz::Europe::London;
/// use chrono_tz::OffsetName;
///
/// # fn main() {
/// let london_time = London.ymd(2016, 2, 10).and_hms(12, 0, 0);
/// assert_eq!(london_time.offset().tz_id(), "Europe/London");
/// // London is normally on GMT
/// assert_eq!(london_time.offset().abbreviation(), "GMT");
///
/// let london_summer_time = London.ymd(2016, 5, 10).and_hms(12, 0, 0);
/// // The TZ ID remains constant year round
/// assert_eq!(london_summer_time.offset().tz_id(), "Europe/London");
/// // During the summer, this becomes British Summer Time
/// assert_eq!(london_summer_time.offset().abbreviation(), "BST");
/// # }
/// ```
pub trait OffsetName {
/// The IANA TZDB identifier (ex: America/New_York)
fn tz_id(&self) -> &str;
/// The abbreviation to use in a longer timestamp (ex: EST)
///
/// This takes into account any special offsets that may be in effect.
/// For example, at a given instant, the time zone with ID *America/New_York*
/// may be either *EST* or *EDT*.
fn abbreviation(&self) -> &str;
}
impl TzOffset {
fn new(tz: Tz, offset: FixedTimespan) -> Self {
TzOffset { tz, offset }
}
fn map_localresult(tz: Tz, result: LocalResult<FixedTimespan>) -> LocalResult<Self> {
match result {
LocalResult::None => LocalResult::None,
LocalResult::Single(s) => LocalResult::Single(TzOffset::new(tz, s)),
LocalResult::Ambiguous(a, b) => {
LocalResult::Ambiguous(TzOffset::new(tz, a), TzOffset::new(tz, b))
}
}
}
}
impl OffsetComponents for TzOffset {
fn base_utc_offset(&self) -> Duration {
Duration::seconds(self.offset.utc_offset as i64)
}
fn dst_offset(&self) -> Duration {
Duration::seconds(self.offset.dst_offset as i64)
}
}
impl OffsetName for TzOffset {
fn tz_id(&self) -> &str {
self.tz.name()
}
fn abbreviation(&self) -> &str {
self.offset.name
}
}
impl Offset for TzOffset {
fn fix(&self) -> FixedOffset {
self.offset.fix()
}
}
impl Display for TzOffset {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
Display::fmt(&self.offset, f)
}
}
impl Debug for TzOffset {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
Debug::fmt(&self.offset, f)
}
}
/// Represents the span of time that a given rule is valid for.
/// Note that I have made the assumption that all ranges are
/// left-inclusive and right-exclusive - that is to say,
/// if the clocks go forward by 1 hour at 1am, the time 1am
/// does not exist in local time (the clock goes from 00:59:59
/// to 02:00:00). Likewise, if the clocks go back by one hour
/// at 2am, the clock goes from 01:59:59 to 01:00:00. This is
/// an arbitrary choice, and I could not find a source to
/// confirm whether or not this is correct.
struct Span {
begin: Option<i64>,
end: Option<i64>,
}
impl Span {
fn contains(&self, x: i64) -> bool {
match (self.begin, self.end) {
(Some(a), Some(b)) if a <= x && x < b => true,
(Some(a), None) if a <= x => true,
(None, Some(b)) if b > x => true,
(None, None) => true,
_ => false,
}
}
fn cmp(&self, x: i64) -> Ordering {
match (self.begin, self.end) {
(Some(a), Some(b)) if a <= x && x < b => Ordering::Equal,
(Some(a), Some(b)) if a <= x && b <= x => Ordering::Less,
(Some(_), Some(_)) => Ordering::Greater,
(Some(a), None) if a <= x => Ordering::Equal,
(Some(_), None) => Ordering::Greater,
(None, Some(b)) if b <= x => Ordering::Less,
(None, Some(_)) => Ordering::Equal,
(None, None) => Ordering::Equal,
}
}
}
#[derive(Copy, Clone)]
pub struct FixedTimespanSet {
pub first: FixedTimespan,
pub rest: &'static [(i64, FixedTimespan)],
}
impl FixedTimespanSet {
fn len(&self) -> usize {
1 + self.rest.len()
}
fn utc_span(&self, index: usize) -> Span {
debug_assert!(index < self.len());
Span {
begin: if index == 0 { None } else { Some(self.rest[index - 1].0) },
end: if index == self.rest.len() { None } else { Some(self.rest[index].0) },
}
}
fn local_span(&self, index: usize) -> Span {
debug_assert!(index < self.len());
Span {
begin: if index == 0 {
None
} else {
let span = self.rest[index - 1];
Some(span.0 + span.1.utc_offset as i64 + span.1.dst_offset as i64)
},
end: if index == self.rest.len() {
None
} else if index == 0 {
Some(
self.rest[index].0
+ self.first.utc_offset as i64
+ self.first.dst_offset as i64,
)
} else {
Some(
self.rest[index].0
+ self.rest[index - 1].1.utc_offset as i64
+ self.rest[index - 1].1.dst_offset as i64,
)
},
}
}
fn get(&self, index: usize) -> FixedTimespan {
debug_assert!(index < self.len());
if index == 0 {
self.first
} else {
self.rest[index - 1].1
}
}
}
pub trait TimeSpans {
fn timespans(&self) -> FixedTimespanSet;
}
impl TimeZone for Tz {
type Offset = TzOffset;
fn from_offset(offset: &Self::Offset) -> Self {
offset.tz
}
#[allow(deprecated)]
fn offset_from_local_date(&self, local: &NaiveDate) -> LocalResult<Self::Offset> {
let earliest = self.offset_from_local_datetime(&local.and_time(NaiveTime::MIN));
let latest = self.offset_from_local_datetime(&local.and_hms_opt(23, 59, 59).unwrap());
// From the chrono docs:
//
// > This type should be considered ambiguous at best, due to the inherent lack of
// > precision required for the time zone resolution. There are some guarantees on the usage
// > of `Date<Tz>`:
// > - If properly constructed via `TimeZone::ymd` and others without an error,
// > the corresponding local date should exist for at least a moment.
// > (It may still have a gap from the offset changes.)
//
// > - The `TimeZone` is free to assign *any* `Offset` to the local date,
// > as long as that offset did occur in given day.
// > For example, if `2015-03-08T01:59-08:00` is followed by `2015-03-08T03:00-07:00`,
// > it may produce either `2015-03-08-08:00` or `2015-03-08-07:00`
// > but *not* `2015-03-08+00:00` and others.
//
// > - Once constructed as a full `DateTime`,
// > `DateTime::date` and other associated methods should return those for the original `Date`.
// > For example, if `dt = tz.ymd(y,m,d).hms(h,n,s)` were valid, `dt.date() == tz.ymd(y,m,d)`.
//
// > - The date is timezone-agnostic up to one day (i.e. practically always),
// > so the local date and UTC date should be equal for most cases
// > even though the raw calculation between `NaiveDate` and `Duration` may not.
//
// For these reasons we return always a single offset here if we can, rather than being
// technically correct and returning Ambiguous(_,_) on days when the clock changes. The
// alternative is painful errors when computing unambiguous times such as
// `TimeZone.ymd(ambiguous_date).hms(unambiguous_time)`.
use chrono::LocalResult::*;
match (earliest, latest) {
(result @ Single(_), _) => result,
(_, result @ Single(_)) => result,
(Ambiguous(offset, _), _) => Single(offset),
(_, Ambiguous(offset, _)) => Single(offset),
(None, None) => None,
}
}
// First search for a timespan that the local datetime falls into, then, if it exists,
// check the two surrounding timespans (if they exist) to see if there is any ambiguity.
fn offset_from_local_datetime(&self, local: &NaiveDateTime) -> LocalResult<Self::Offset> {
let timestamp = local.and_utc().timestamp();
let timespans = self.timespans();
let index = binary_search(0, timespans.len(), |i| timespans.local_span(i).cmp(timestamp));
TzOffset::map_localresult(
*self,
match index {
Ok(0) if timespans.len() == 1 => LocalResult::Single(timespans.get(0)),
Ok(0) if timespans.local_span(1).contains(timestamp) => {
LocalResult::Ambiguous(timespans.get(0), timespans.get(1))
}
Ok(0) => LocalResult::Single(timespans.get(0)),
Ok(i) if timespans.local_span(i - 1).contains(timestamp) => {
LocalResult::Ambiguous(timespans.get(i - 1), timespans.get(i))
}
Ok(i) if i == timespans.len() - 1 => LocalResult::Single(timespans.get(i)),
Ok(i) if timespans.local_span(i + 1).contains(timestamp) => {
LocalResult::Ambiguous(timespans.get(i), timespans.get(i + 1))
}
Ok(i) => LocalResult::Single(timespans.get(i)),
Err(_) => LocalResult::None,
},
)
}
#[allow(deprecated)]
fn offset_from_utc_date(&self, utc: &NaiveDate) -> Self::Offset {
// See comment above for why it is OK to just take any arbitrary time in the day
self.offset_from_utc_datetime(&utc.and_time(NaiveTime::MIN))
}
// Binary search for the required timespan. Any i64 is guaranteed to fall within
// exactly one timespan, no matter what (so the `unwrap` is safe).
fn offset_from_utc_datetime(&self, dt: &NaiveDateTime) -> Self::Offset {
let timestamp = dt.and_utc().timestamp();
let timespans = self.timespans();
let index =
binary_search(0, timespans.len(), |i| timespans.utc_span(i).cmp(timestamp)).unwrap();
TzOffset::new(*self, timespans.get(index))
}
}
+2
View File
@@ -0,0 +1,2 @@
#![allow(non_camel_case_types, clippy::unreadable_literal)]
include!(concat!(env!("OUT_DIR"), "/timezones.rs"));
@@ -0,0 +1,162 @@
//! Unit tests derived from Tom Scott's video on Numberphile,
//! [`The Problem with Time & Timezones'][video].
//! Note that not all tests are passing; the ones towards
//! the end of the video are not handled correctly (nor are
//! currently intended to be handled correctly) by chrono.
//!
//! [video]: https://www.youtube.com/watch?v=-5wpm-gesOY
use chrono::{DateTime, NaiveDate, TimeZone};
use chrono_tz::Africa::Tripoli;
use chrono_tz::America::New_York;
use chrono_tz::Asia::Gaza;
use chrono_tz::Asia::Jerusalem;
use chrono_tz::Asia::Kathmandu;
use chrono_tz::Australia::Adelaide;
use chrono_tz::Etc::UTC;
use chrono_tz::Europe::London;
use chrono_tz::Europe::Moscow;
use chrono_tz::Pacific::Apia;
fn seconds<Tz1: TimeZone, Tz2: TimeZone>(from: DateTime<Tz1>, to: DateTime<Tz2>) -> i64 {
to.signed_duration_since(from).num_seconds()
}
#[test]
fn london_5_days_ago_to_new_york() {
let from = London.with_ymd_and_hms(2013, 12, 25, 14, 0, 0).unwrap();
let to = New_York.with_ymd_and_hms(2013, 12, 30, 14, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * (24 * 5 + 5));
}
#[test]
fn london_to_australia() {
// at the time Tom was speaking, Adelaide was 10 1/2 hours ahead
// many other parts of Australia use different time zones
let from = London.with_ymd_and_hms(2013, 12, 25, 14, 0, 0).unwrap();
let to = Adelaide.with_ymd_and_hms(2013, 12, 30, 14, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * (24 * 5 - 10) - 60 * 30);
}
#[test]
fn london_to_nepal() {
// note Tom gets this wrong, it's 5 3/4 hours as he is speaking
let from = London.with_ymd_and_hms(2013, 12, 25, 14, 0, 0).unwrap();
let to = Kathmandu.with_ymd_and_hms(2013, 12, 30, 14, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * (24 * 5 - 5) - 60 * 45);
}
#[test]
fn autumn() {
let from = London.with_ymd_and_hms(2013, 10, 25, 12, 0, 0).unwrap();
let to = London.with_ymd_and_hms(2013, 11, 1, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * (24 * 7 + 1));
}
#[test]
fn earlier_daylight_savings_in_new_york() {
let from = New_York.with_ymd_and_hms(2013, 10, 25, 12, 0, 0).unwrap();
let to = New_York.with_ymd_and_hms(2013, 11, 1, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * (24 * 7));
}
#[test]
fn southern_hemisphere_clocks_forward() {
let from = Adelaide.with_ymd_and_hms(2013, 10, 1, 12, 0, 0).unwrap();
let to = Adelaide.with_ymd_and_hms(2013, 11, 1, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * (24 * 31 - 1));
}
#[test]
fn samoa_skips_a_day() {
let from = Apia.with_ymd_and_hms(2011, 12, 29, 12, 0, 0).unwrap();
let to = Apia.with_ymd_and_hms(2011, 12, 31, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * 24);
}
#[test]
fn double_bst() {
let from = London.with_ymd_and_hms(1942, 6, 1, 12, 0, 0).unwrap();
let to = UTC.with_ymd_and_hms(1942, 6, 1, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * 2);
}
#[test]
fn libya_2013() {
// Libya actually put their clocks *forward* in 2013, but not in any other year
let from = Tripoli.with_ymd_and_hms(2012, 3, 1, 12, 0, 0).unwrap();
let to = Tripoli.with_ymd_and_hms(2012, 4, 1, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * 24 * 31);
let from = Tripoli.with_ymd_and_hms(2013, 3, 1, 12, 0, 0).unwrap();
let to = Tripoli.with_ymd_and_hms(2013, 4, 1, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * (24 * 31 - 1));
let from = Tripoli.with_ymd_and_hms(2014, 3, 1, 12, 0, 0).unwrap();
let to = Tripoli.with_ymd_and_hms(2014, 4, 1, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * 24 * 31);
}
#[test]
fn israel_palestine() {
let from = Jerusalem.with_ymd_and_hms(2016, 10, 29, 12, 0, 0).unwrap();
let to = Gaza.with_ymd_and_hms(2016, 10, 29, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60);
}
// FIXME doesn't currently work!
#[test]
#[ignore]
fn london_julian_to_gregorian() {
let from = London.with_ymd_and_hms(1752, 9, 2, 12, 0, 0).unwrap();
let to = London.with_ymd_and_hms(1752, 9, 14, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * 24);
}
// FIXME doesn't currently work!
#[test]
#[ignore]
fn russian_julian_to_gregorian() {
let from = Moscow.with_ymd_and_hms(1918, 1, 31, 12, 0, 0).unwrap();
let to = Moscow.with_ymd_and_hms(1918, 2, 14, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * 24);
}
// FIXME doesn't currently work!
#[test]
#[ignore]
fn london_25_march() {
let from = London.with_ymd_and_hms(924, 3, 24, 12, 0, 0).unwrap();
let to = London.with_ymd_and_hms(925, 3, 25, 12, 0, 0).unwrap();
assert_eq!(seconds(from, to), 60 * 60 * 24);
}
#[test]
fn leapsecond() {
let from = UTC.with_ymd_and_hms(2016, 6, 30, 23, 59, 59).unwrap();
let leap =
NaiveDate::from_ymd_opt(2016, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1000).unwrap();
let to = UTC.from_local_datetime(&leap).unwrap();
assert_eq!(seconds(from, to), 1);
}
// FIXME doesn't currently work!
#[test]
#[ignore]
fn leapsecond_2() {
let from = UTC.with_ymd_and_hms(2016, 6, 30, 23, 59, 59).unwrap();
let to = UTC.with_ymd_and_hms(2016, 7, 1, 0, 0, 0).unwrap();
assert_eq!(seconds(from, to), 2);
}
// FIXME doesn't currently work!
#[test]
#[ignore]
fn leapsecond_3() {
let leap =
NaiveDate::from_ymd_opt(2016, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1000).unwrap();
let from = UTC.from_local_datetime(&leap).unwrap();
let to = UTC.with_ymd_and_hms(2016, 7, 1, 0, 0, 0).unwrap();
assert_eq!(seconds(from, to), 1);
}
+5
View File
@@ -0,0 +1,5 @@
Unless specified below, all files in the tz code and data (including
this LICENSE file) are in the public domain.
If the files date.c, newstrftime.3, and strftime.c are present, they
contain material derived from BSD and use the BSD 3-clause license.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+362
View File
@@ -0,0 +1,362 @@
# tzdb data for Antarctica and environs
# This file is in the public domain, so clarified as of
# 2009-05-17 by Arthur David Olson.
# From Paul Eggert (1999-11-15):
# To keep things manageable, we list only locations occupied year-round; see
# COMNAP - Stations and Bases
# http://www.comnap.aq/comnap/comnap.nsf/P/Stations/
# and
# Summary of the Peri-Antarctic Islands (1998-07-23)
# http://www.spri.cam.ac.uk/bob/periant.htm
# for information.
# Unless otherwise specified, we have no time zone information.
# FORMAT is '-00' and STDOFF is 0 for locations while uninhabited.
# Argentina - year-round bases
# Belgrano II, Confin Coast, -770227-0343737, since 1972-02-05
# Carlini, Potter Cove, King George Island, -6414-0602320, since 1982-01
# Esperanza, Hope Bay, -6323-05659, since 1952-12-17
# Marambio, -6414-05637, since 1969-10-29
# Orcadas, Laurie I, -6016-04444, since 1904-02-22
# San Martín, Barry I, -6808-06706, since 1951-03-21
# (except 1960-03 / 1976-03-21)
# Australia - territories
# Heard Island, McDonald Islands (uninhabited)
# previously sealers and scientific personnel wintered
# Margaret Turner reports
# https://web.archive.org/web/20021204222245/http://www.dstc.qut.edu.au/DST/marg/daylight.html
# (1999-09-30) that they're UT +05, with no DST;
# presumably this is when they have visitors.
#
# year-round bases
# Casey, Bailey Peninsula, -6617+11032, since 1969
# Davis, Vestfold Hills, -6835+07759, since 1957-01-13
# (except 1964-11 - 1969-02)
# Mawson, Holme Bay, -6736+06253, since 1954-02-13
# From Steffen Thorsen (2009-03-11):
# Three Australian stations in Antarctica have changed their time zone:
# Casey moved from UTC+8 to UTC+11
# Davis moved from UTC+7 to UTC+5
# Mawson moved from UTC+6 to UTC+5
# The changes occurred on 2009-10-18 at 02:00 (local times).
#
# Government source: (Australian Antarctic Division)
# http://www.aad.gov.au/default.asp?casid=37079
#
# We have more background information here:
# https://www.timeanddate.com/news/time/antarctica-new-times.html
# From Steffen Thorsen (2010-03-10):
# We got these changes from the Australian Antarctic Division: ...
#
# - Casey station reverted to its normal time of UTC+8 on 5 March 2010.
# The change to UTC+11 is being considered as a regular summer thing but
# has not been decided yet.
#
# - Davis station will revert to its normal time of UTC+7 at 10 March 2010
# 20:00 UTC.
#
# - Mawson station stays on UTC+5.
#
# Background:
# https://www.timeanddate.com/news/time/antartica-time-changes-2010.html
# From Steffen Thorsen (2016-10-28):
# Australian Antarctica Division informed us that Casey changed time
# zone to UTC+11 in "the morning of 22nd October 2016".
# From Steffen Thorsen (2020-10-02, as corrected):
# Based on information we have received from the Australian Antarctic
# Division, Casey station and Macquarie Island station will move to Tasmanian
# daylight savings time on Sunday 4 October. This will take effect from 0001
# hrs on Sunday 4 October 2020 and will mean Casey and Macquarie Island will
# be on the same time zone as Hobart. Some past dates too for this 3 hour
# time change back and forth between UTC+8 and UTC+11 for Casey:
# - 2018 Oct 7 4:00 - 2019 Mar 17 3:00 - 2019 Oct 4 3:00 - 2020 Mar 8 3:00
# and now - 2020 Oct 4 0:01
# From Paul Eggert (2023-12-20):
# Transitions from 2021 on are taken from:
# https://www.timeanddate.com/time/zone/antarctica/casey
# retrieved at various dates.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Antarctica/Casey 0 - -00 1969
8:00 - +08 2009 Oct 18 2:00
11:00 - +11 2010 Mar 5 2:00
8:00 - +08 2011 Oct 28 2:00
11:00 - +11 2012 Feb 21 17:00u
8:00 - +08 2016 Oct 22
11:00 - +11 2018 Mar 11 4:00
8:00 - +08 2018 Oct 7 4:00
11:00 - +11 2019 Mar 17 3:00
8:00 - +08 2019 Oct 4 3:00
11:00 - +11 2020 Mar 8 3:00
8:00 - +08 2020 Oct 4 0:01
11:00 - +11 2021 Mar 14 0:00
8:00 - +08 2021 Oct 3 0:01
11:00 - +11 2022 Mar 13 0:00
8:00 - +08 2022 Oct 2 0:01
11:00 - +11 2023 Mar 9 3:00
8:00 - +08
Zone Antarctica/Davis 0 - -00 1957 Jan 13
7:00 - +07 1964 Nov
0 - -00 1969 Feb
7:00 - +07 2009 Oct 18 2:00
5:00 - +05 2010 Mar 10 20:00u
7:00 - +07 2011 Oct 28 2:00
5:00 - +05 2012 Feb 21 20:00u
7:00 - +07
Zone Antarctica/Mawson 0 - -00 1954 Feb 13
6:00 - +06 2009 Oct 18 2:00
5:00 - +05
# References:
# Casey Weather (1998-02-26)
# http://www.antdiv.gov.au/aad/exop/sfo/casey/casey_aws.html
# Davis Station, Antarctica (1998-02-26)
# http://www.antdiv.gov.au/aad/exop/sfo/davis/video.html
# Mawson Station, Antarctica (1998-02-25)
# http://www.antdiv.gov.au/aad/exop/sfo/mawson/video.html
# Belgium - year-round base
# Princess Elisabeth, Queen Maud Land, -713412+0231200, since 2007
# Brazil - year-round base
# Ferraz, King George Island, -6205+05824, since 1983/4
# Bulgaria - year-round base
# St. Kliment Ohridski, Livingston Island, -623829-0602153, since 1988
# Chile - year-round bases and towns
# Escudero, South Shetland Is, -621157-0585735, since 1994
# Frei Montalva, King George Island, -6214-05848, since 1969-03-07
# O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
# Prat, -6230-05941
# Villa Las Estrellas (a town), around the Frei base, since 1984-04-09
# These locations employ Region of Magallanes time; use
# TZ='America/Punta_Arenas'.
# China - year-round bases
# Great Wall, King George Island, -6213-05858, since 1985-02-20
# Zhongshan, Larsemann Hills, Prydz Bay, -6922+07623, since 1989-02-26
# France - year-round bases (also see "France & Italy")
#
# From Antoine Leca (1997-01-20):
# Time data entries are from Nicole Pailleau at the IFRTP
# (French Institute for Polar Research and Technology).
# She confirms that French Southern Territories and Terre Adélie bases
# don't observe daylight saving time, even if Terre Adélie supplies came
# from Tasmania.
#
# French Southern Territories with year-round inhabitants
#
# Alfred Faure, Possession Island, Crozet Islands, -462551+0515152, since 1964;
# sealing & whaling stations operated variously 1802/1911+;
# see Asia/Dubai.
#
# Martin-de-Viviès, Amsterdam Island, -374105+0773155, since 1950
# Port-aux-Français, Kerguelen Islands, -492110+0701303, since 1951;
# whaling & sealing station operated 1908/1914, 1920/1929, and 1951/1956
#
# St Paul Island - near Amsterdam, uninhabited
# fishing stations operated variously 1819/1931
#
# Kerguelen - see Indian/Maldives.
#
# year-round base in the main continent
# Dumont d'Urville - see Pacific/Port_Moresby.
# France & Italy - year-round base
# Concordia, -750600+1232000, since 2005
# Germany - year-round base
# Neumayer III, -704080-0081602, since 2009
# India - year-round bases
# Bharati, -692428+0761114, since 2012
# Maitri, -704558+0114356, since 1989
# Italy - year-round base (also see "France & Italy")
# Zuchelli, Terra Nova Bay, -744140+1640647, since 1986
# Japan - year-round bases
# See Asia/Riyadh.
# S Korea - year-round base
# Jang Bogo, Terra Nova Bay, -743700+1641205 since 2014
# King Sejong, King George Island, -6213-05847, since 1988
# New Zealand - claims
# Balleny Islands (never inhabited)
# Scott Island (never inhabited)
#
# year-round base
# Scott Base, Ross Island, since 1957-01.
# See Pacific/Auckland.
# Norway - territories
# Bouvet (never inhabited)
#
# claims
# Peter I Island (never inhabited)
#
# year-round base
# Troll, Queen Maud Land, -720041+0023206, since 2005-02-12
#
# From Paul-Inge Flakstad (2014-03-10):
# I recently had a long dialog about this with the developer of timegenie.com.
# In the absence of specific dates, he decided to choose some likely ones:
# GMT +1 - From March 1 to the last Sunday in March
# GMT +2 - From the last Sunday in March until the last Sunday in October
# GMT +1 - From the last Sunday in October until November 7
# GMT +0 - From November 7 until March 1
# The dates for switching to and from UTC+0 will probably not be absolutely
# correct, but they should be quite close to the actual dates.
#
# From Paul Eggert (2014-03-21):
# The CET-switching Troll rules require zic from tz 2014b or later, so as
# suggested by Bengt-Inge Larsson comment them out for now, and approximate
# with only UTC and CEST. Uncomment them when 2014b is more prevalent.
#
# Rule NAME FROM TO - IN ON AT SAVE LETTER/S
#Rule Troll 2005 max - Mar 1 1:00u 1:00 +01
Rule Troll 2005 max - Mar lastSun 1:00u 2:00 +02
#Rule Troll 2005 max - Oct lastSun 1:00u 1:00 +01
#Rule Troll 2004 max - Nov 7 1:00u 0:00 +00
# Remove the following line when uncommenting the above '#Rule' lines.
Rule Troll 2004 max - Oct lastSun 1:00u 0:00 +00
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Antarctica/Troll 0 - -00 2005 Feb 12
0:00 Troll %s
# Poland - year-round base
# Arctowski, King George Island, -620945-0582745, since 1977
# Romania - year-bound base
# Law-Racoviță, Larsemann Hills, -692319+0762251, since 1986
# Russia - year-round bases
# Bellingshausen, King George Island, -621159-0585337, since 1968-02-22
# Mirny, Davis coast, -6633+09301, since 1956-02
# Molodezhnaya, Alasheyev Bay, -6740+04551,
# year-round from 1962-02 to 1999-07-01
# Novolazarevskaya, Queen Maud Land, -7046+01150,
# year-round from 1960/61 to 1992
# Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11
# From Craig Mundell (1994-12-15):
# http://quest.arc.nasa.gov/antarctica/QA/computers/Directions,Time,ZIP
# Vostok, which is one of the Russian stations, is set on the same
# time as Moscow, Russia.
#
# From Lee Hotz (2001-03-08):
# I queried the folks at Columbia who spent the summer at Vostok and this is
# what they had to say about time there:
# "in the US Camp (East Camp) we have been on New Zealand (McMurdo)
# time, which is 12 hours ahead of GMT. The Russian Station Vostok was
# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead
# of GMT). This is a time zone I think two hours east of Moscow. The
# natural time zone is in between the two: 8 hours ahead of GMT."
#
# From Paul Eggert (2001-05-04):
# This seems to be hopelessly confusing, so I asked Lee Hotz about it
# in person. He said that some Antarctic locations set their local
# time so that noon is the warmest part of the day, and that this
# changes during the year and does not necessarily correspond to mean
# solar noon. So the Vostok time might have been whatever the clocks
# happened to be during their visit. So we still don't really know what time
# it is at Vostok.
#
# From Zakhary V. Akulov (2023-12-17 22:00:48 +0700):
# ... from December, 18, 2023 00:00 by my decision the local time of
# the Antarctic research base Vostok will correspond to UTC+5.
# (2023-12-19): We constantly interact with Progress base, with company who
# builds new wintering station, with sledge convoys, with aviation - they all
# use UTC+5. Besides, difference between Moscow time is just 2 hours now, not 4.
# (2023-12-19, in response to the question "Has local time at Vostok
# been UTC+6 ever since 1957, or has it changed before?"): No. At least
# since my antarctic career start, 10 years ago, Vostok base has UTC+7.
# (In response to a 2023-12-18 question "from 02:00 to 00:00 today"): This.
#
# From Paul Eggert (2023-12-18):
# For lack of better info, guess Vostok was at +07 from founding through today,
# except when closed.
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Antarctica/Vostok 0 - -00 1957 Dec 16
7:00 - +07 1994 Feb
0 - -00 1994 Nov
7:00 - +07 2023 Dec 18 2:00
5:00 - +05
# S Africa - year-round bases
# Marion Island, -4653+03752
# SANAE IV, Vesleskarvet, Queen Maud Land, -714022-0025026, since 1997
# Ukraine - year-round base
# Vernadsky (formerly Faraday), Galindez Island, -651445-0641526, since 1954
# United Kingdom
#
# British Antarctic Territories (BAT) claims
# South Orkney Islands
# scientific station from 1903
# whaling station at Signy I 1920/1926
# South Shetland Islands
#
# year-round bases
# Bird Island, South Georgia, -5400-03803, since 1983
# Deception Island, -6259-06034, whaling station 1912/1931,
# scientific station 1943/1967,
# previously sealers and a scientific expedition wintered by accident,
# and a garrison was deployed briefly
# Halley, Coates Land, -7535-02604, since 1956-01-06
# Halley is on a moving ice shelf and is periodically relocated
# so that it is never more than 10km from its nominal location.
# Rothera, Adelaide Island, -6734-6808, since 1976-12-01
#
# From Paul Eggert (2002-10-22)
# <http://webexhibits.org/daylightsaving/g.html> says Rothera is -03 all year.
#
# Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Antarctica/Rothera 0 - -00 1976 Dec 1
-3:00 - -03
# Uruguay - year round base
# Artigas, King George Island, -621104-0585107
# USA - year-round bases
#
# Palmer, Anvers Island, since 1965 (moved 2 miles in 1968)
# See 'southamerica' for Antarctica/Palmer, since it uses South American DST.
#
# McMurdo Station, Ross Island, since 1955-12
# Amundsen-Scott South Pole Station, continuously occupied since 1956-11-20
#
# From Chris Carrier (1996-06-27):
# Siple, the first commander of the South Pole station,
# stated that he would have liked to have kept GMT at the station,
# but that he found it more convenient to keep GMT+12
# as supplies for the station were coming from McMurdo Sound,
# which was on GMT+12 because New Zealand was on GMT+12 all year
# at that time (1957). (Source: Siple's book 90° South.)
#
# From Susan Smith
# http://www.cybertours.com/whs/pole10.html
# (1995-11-13 16:24:56 +1300, no longer available):
# We use the same time as McMurdo does.
# And they use the same time as Christchurch, NZ does....
# One last quirk about South Pole time.
# All the electric clocks are usually wrong.
# Something about the generators running at 60.1hertz or something
# makes all of the clocks run fast. So every couple of days,
# we have to go around and set them back 5 minutes or so.
# Maybe if we let them run fast all of the time, we'd get to leave here sooner!!
#
# See Pacific/Auckland.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+318
View File
@@ -0,0 +1,318 @@
# tzdb links for backward compatibility
# This file is in the public domain, so clarified as of
# 2009-05-17 by Arthur David Olson.
# This file provides links from old or merged timezone names to current ones.
# Many names changed in 1993 and in 1995, and many merged names moved here
# in the period from 2013 through 2022. Several of these names are
# also present in the file 'backzone', which has data important only
# for pre-1970 timestamps and so is out of scope for tzdb proper.
# Although this file is optional and tzdb will work if you omit it by
# building with 'make BACKWARD=', in practice downstream users
# typically use this file for backward compatibility.
# This file is divided into sections, one for each major reason for a
# backward compatibility link. Each section is sorted by link name.
# A "#= TARGET1" comment labels each link inserted only because some
# .zi parsers (including tzcode through 2022e) mishandle links to links.
# The comment says what the target would be if these parsers were fixed
# so that data could contain links to links. For example, the line
# "Link Australia/Sydney Australia/ACT #= Australia/Canberra" would be
# "Link Australia/Canberra Australia/ACT" were it not that data lines
# refrain from linking to links like Australia/Canberra, which means
# the Australia/ACT line links instead to Australia/Sydney,
# Australia/Canberra's target.
# Pre-1993 naming conventions
# Link TARGET LINK-NAME #= TARGET1
Link Australia/Sydney Australia/ACT #= Australia/Canberra
Link Australia/Lord_Howe Australia/LHI
Link Australia/Sydney Australia/NSW
Link Australia/Darwin Australia/North
Link Australia/Brisbane Australia/Queensland
Link Australia/Adelaide Australia/South
Link Australia/Hobart Australia/Tasmania
Link Australia/Melbourne Australia/Victoria
Link Australia/Perth Australia/West
Link Australia/Broken_Hill Australia/Yancowinna
Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre
Link America/Noronha Brazil/DeNoronha
Link America/Sao_Paulo Brazil/East
Link America/Manaus Brazil/West
Link America/Halifax Canada/Atlantic
Link America/Winnipeg Canada/Central
# This line is commented out, as the name exceeded the 14-character limit
# and was an unused misnomer.
#Link America/Regina Canada/East-Saskatchewan
Link America/Toronto Canada/Eastern
Link America/Edmonton Canada/Mountain
Link America/St_Johns Canada/Newfoundland
Link America/Vancouver Canada/Pacific
Link America/Regina Canada/Saskatchewan
Link America/Whitehorse Canada/Yukon
Link America/Santiago Chile/Continental
Link Pacific/Easter Chile/EasterIsland
Link America/Havana Cuba
Link Africa/Cairo Egypt
Link Europe/Dublin Eire
# Vanguard section, for most .zi parsers.
#Link GMT Etc/GMT
#Link GMT Etc/GMT+0
#Link GMT Etc/GMT-0
#Link GMT Etc/GMT0
#Link GMT Etc/Greenwich
# Rearguard section, for TZUpdater 2.3.2 and earlier.
Link Etc/GMT Etc/GMT+0
Link Etc/GMT Etc/GMT-0
Link Etc/GMT Etc/GMT0
Link Etc/GMT Etc/Greenwich
# End of rearguard section.
Link Etc/UTC Etc/UCT
Link Etc/UTC Etc/Universal
Link Etc/UTC Etc/Zulu
Link Europe/London GB
Link Europe/London GB-Eire
# Vanguard section, for most .zi parsers.
#Link GMT GMT+0
#Link GMT GMT-0
#Link GMT GMT0
#Link GMT Greenwich
# Rearguard section, for TZUpdater 2.3.2 and earlier.
Link Etc/GMT GMT+0
Link Etc/GMT GMT-0
Link Etc/GMT GMT0
Link Etc/GMT Greenwich
# End of rearguard section.
Link Asia/Hong_Kong Hongkong
Link Africa/Abidjan Iceland #= Atlantic/Reykjavik
Link Asia/Tehran Iran
Link Asia/Jerusalem Israel
Link America/Jamaica Jamaica
Link Asia/Tokyo Japan
Link Pacific/Kwajalein Kwajalein
Link Africa/Tripoli Libya
Link America/Tijuana Mexico/BajaNorte
Link America/Mazatlan Mexico/BajaSur
Link America/Mexico_City Mexico/General
Link Pacific/Auckland NZ
Link Pacific/Chatham NZ-CHAT
Link America/Denver Navajo #= America/Shiprock
Link Asia/Shanghai PRC
Link Europe/Warsaw Poland
Link Europe/Lisbon Portugal
Link Asia/Taipei ROC
Link Asia/Seoul ROK
Link Asia/Singapore Singapore
Link Europe/Istanbul Turkey
Link Etc/UTC UCT
Link America/Anchorage US/Alaska
Link America/Adak US/Aleutian
Link America/Phoenix US/Arizona
Link America/Chicago US/Central
Link America/Indiana/Indianapolis US/East-Indiana
Link America/New_York US/Eastern
Link Pacific/Honolulu US/Hawaii
Link America/Indiana/Knox US/Indiana-Starke
Link America/Detroit US/Michigan
Link America/Denver US/Mountain
Link America/Los_Angeles US/Pacific
Link Pacific/Pago_Pago US/Samoa
Link Etc/UTC UTC
Link Etc/UTC Universal
Link Europe/Moscow W-SU
Link Etc/UTC Zulu
# Two-part names that were renamed mostly to three-part names in 1995
# Link TARGET LINK-NAME #= TARGET1
Link America/Argentina/Buenos_Aires America/Buenos_Aires
Link America/Argentina/Catamarca America/Catamarca
Link America/Argentina/Cordoba America/Cordoba
Link America/Indiana/Indianapolis America/Indianapolis
Link America/Argentina/Jujuy America/Jujuy
Link America/Indiana/Knox America/Knox_IN
Link America/Kentucky/Louisville America/Louisville
Link America/Argentina/Mendoza America/Mendoza
Link America/Puerto_Rico America/Virgin #= America/St_Thomas
Link Pacific/Pago_Pago Pacific/Samoa
# Pre-2013 practice, which typically had a Zone per zone.tab line
# Link TARGET LINK-NAME
Link Africa/Abidjan Africa/Accra
Link Africa/Nairobi Africa/Addis_Ababa
Link Africa/Nairobi Africa/Asmara
Link Africa/Abidjan Africa/Bamako
Link Africa/Lagos Africa/Bangui
Link Africa/Abidjan Africa/Banjul
Link Africa/Maputo Africa/Blantyre
Link Africa/Lagos Africa/Brazzaville
Link Africa/Maputo Africa/Bujumbura
Link Africa/Abidjan Africa/Conakry
Link Africa/Abidjan Africa/Dakar
Link Africa/Nairobi Africa/Dar_es_Salaam
Link Africa/Nairobi Africa/Djibouti
Link Africa/Lagos Africa/Douala
Link Africa/Abidjan Africa/Freetown
Link Africa/Maputo Africa/Gaborone
Link Africa/Maputo Africa/Harare
Link Africa/Nairobi Africa/Kampala
Link Africa/Maputo Africa/Kigali
Link Africa/Lagos Africa/Kinshasa
Link Africa/Lagos Africa/Libreville
Link Africa/Abidjan Africa/Lome
Link Africa/Lagos Africa/Luanda
Link Africa/Maputo Africa/Lubumbashi
Link Africa/Maputo Africa/Lusaka
Link Africa/Lagos Africa/Malabo
Link Africa/Johannesburg Africa/Maseru
Link Africa/Johannesburg Africa/Mbabane
Link Africa/Nairobi Africa/Mogadishu
Link Africa/Lagos Africa/Niamey
Link Africa/Abidjan Africa/Nouakchott
Link Africa/Abidjan Africa/Ouagadougou
Link Africa/Lagos Africa/Porto-Novo
Link America/Puerto_Rico America/Anguilla
Link America/Puerto_Rico America/Antigua
Link America/Puerto_Rico America/Aruba
Link America/Panama America/Atikokan
Link America/Puerto_Rico America/Blanc-Sablon
Link America/Panama America/Cayman
Link America/Phoenix America/Creston
Link America/Puerto_Rico America/Curacao
Link America/Puerto_Rico America/Dominica
Link America/Puerto_Rico America/Grenada
Link America/Puerto_Rico America/Guadeloupe
Link America/Puerto_Rico America/Kralendijk
Link America/Puerto_Rico America/Lower_Princes
Link America/Puerto_Rico America/Marigot
Link America/Puerto_Rico America/Montserrat
Link America/Toronto America/Nassau
Link America/Puerto_Rico America/Port_of_Spain
Link America/Puerto_Rico America/St_Barthelemy
Link America/Puerto_Rico America/St_Kitts
Link America/Puerto_Rico America/St_Lucia
Link America/Puerto_Rico America/St_Thomas
Link America/Puerto_Rico America/St_Vincent
Link America/Puerto_Rico America/Tortola
Link Pacific/Port_Moresby Antarctica/DumontDUrville
Link Pacific/Auckland Antarctica/McMurdo
Link Asia/Riyadh Antarctica/Syowa
Link Europe/Berlin Arctic/Longyearbyen
Link Asia/Riyadh Asia/Aden
Link Asia/Qatar Asia/Bahrain
Link Asia/Kuching Asia/Brunei
Link Asia/Singapore Asia/Kuala_Lumpur
Link Asia/Riyadh Asia/Kuwait
Link Asia/Dubai Asia/Muscat
Link Asia/Bangkok Asia/Phnom_Penh
Link Asia/Bangkok Asia/Vientiane
Link Africa/Abidjan Atlantic/Reykjavik
Link Africa/Abidjan Atlantic/St_Helena
Link Europe/Brussels Europe/Amsterdam
Link Europe/Prague Europe/Bratislava
Link Europe/Zurich Europe/Busingen
Link Europe/Berlin Europe/Copenhagen
Link Europe/London Europe/Guernsey
Link Europe/London Europe/Isle_of_Man
Link Europe/London Europe/Jersey
Link Europe/Belgrade Europe/Ljubljana
Link Europe/Brussels Europe/Luxembourg
Link Europe/Helsinki Europe/Mariehamn
Link Europe/Paris Europe/Monaco
Link Europe/Berlin Europe/Oslo
Link Europe/Belgrade Europe/Podgorica
Link Europe/Rome Europe/San_Marino
Link Europe/Belgrade Europe/Sarajevo
Link Europe/Belgrade Europe/Skopje
Link Europe/Berlin Europe/Stockholm
Link Europe/Zurich Europe/Vaduz
Link Europe/Rome Europe/Vatican
Link Europe/Belgrade Europe/Zagreb
Link Africa/Nairobi Indian/Antananarivo
Link Asia/Bangkok Indian/Christmas
Link Asia/Yangon Indian/Cocos
Link Africa/Nairobi Indian/Comoro
Link Indian/Maldives Indian/Kerguelen
Link Asia/Dubai Indian/Mahe
Link Africa/Nairobi Indian/Mayotte
Link Asia/Dubai Indian/Reunion
Link Pacific/Port_Moresby Pacific/Chuuk
Link Pacific/Tarawa Pacific/Funafuti
Link Pacific/Tarawa Pacific/Majuro
Link Pacific/Pago_Pago Pacific/Midway
Link Pacific/Guadalcanal Pacific/Pohnpei
Link Pacific/Guam Pacific/Saipan
Link Pacific/Tarawa Pacific/Wake
Link Pacific/Tarawa Pacific/Wallis
# Non-zone.tab locations with timestamps since 1970 that duplicate
# those of an existing location
# Link TARGET LINK-NAME
Link Africa/Abidjan Africa/Timbuktu
Link America/Argentina/Catamarca America/Argentina/ComodRivadavia
Link America/Adak America/Atka
Link America/Panama America/Coral_Harbour
Link America/Tijuana America/Ensenada
Link America/Indiana/Indianapolis America/Fort_Wayne
Link America/Toronto America/Montreal
Link America/Toronto America/Nipigon
Link America/Iqaluit America/Pangnirtung
Link America/Rio_Branco America/Porto_Acre
Link America/Winnipeg America/Rainy_River
Link America/Argentina/Cordoba America/Rosario
Link America/Tijuana America/Santa_Isabel
Link America/Denver America/Shiprock
Link America/Toronto America/Thunder_Bay
Link America/Edmonton America/Yellowknife
Link Pacific/Auckland Antarctica/South_Pole
Link Asia/Shanghai Asia/Chongqing
Link Asia/Shanghai Asia/Harbin
Link Asia/Urumqi Asia/Kashgar
Link Asia/Jerusalem Asia/Tel_Aviv
Link Europe/Berlin Atlantic/Jan_Mayen
Link Australia/Sydney Australia/Canberra
Link Australia/Hobart Australia/Currie
Link Europe/London Europe/Belfast
Link Europe/Chisinau Europe/Tiraspol
Link Europe/Kyiv Europe/Uzhgorod
Link Europe/Kyiv Europe/Zaporozhye
Link Pacific/Kanton Pacific/Enderbury
Link Pacific/Honolulu Pacific/Johnston
Link Pacific/Port_Moresby Pacific/Yap
# Alternate names for the same location
# Link TARGET LINK-NAME #= TARGET1
Link Africa/Nairobi Africa/Asmera #= Africa/Asmara
Link America/Nuuk America/Godthab
Link Asia/Ashgabat Asia/Ashkhabad
Link Asia/Kolkata Asia/Calcutta
Link Asia/Shanghai Asia/Chungking #= Asia/Chongqing
Link Asia/Dhaka Asia/Dacca
# Istanbul is in both continents.
Link Europe/Istanbul Asia/Istanbul
Link Asia/Kathmandu Asia/Katmandu
Link Asia/Macau Asia/Macao
Link Asia/Yangon Asia/Rangoon
Link Asia/Ho_Chi_Minh Asia/Saigon
Link Asia/Thimphu Asia/Thimbu
Link Asia/Makassar Asia/Ujung_Pandang
Link Asia/Ulaanbaatar Asia/Ulan_Bator
Link Atlantic/Faroe Atlantic/Faeroe
Link Europe/Kyiv Europe/Kiev
# Classically, Cyprus is in Asia; e.g. see Herodotus, Histories, I.72.
# However, for various reasons many users expect to find it under Europe.
Link Asia/Nicosia Europe/Nicosia
Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei
Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk
+79
View File
@@ -0,0 +1,79 @@
# tzdb data for ships at sea and other miscellany
# This file is in the public domain, so clarified as of
# 2009-05-17 by Arthur David Olson.
# These entries are for uses not otherwise covered by the tz database.
# Their main practical use is for platforms like Android that lack
# support for POSIX.1-2017-style TZ strings. On such platforms these entries
# can be useful if the timezone database is wrong or if a ship or
# aircraft at sea is not in a timezone.
# Starting with POSIX 1003.1-2001, the entries below are all
# unnecessary as settings for the TZ environment variable. E.g.,
# instead of TZ='Etc/GMT+4' one can use the POSIX setting TZ='<-04>+4'.
#
# Do not use a POSIX TZ setting like TZ='GMT+4', which is four hours
# behind GMT but uses the completely misleading abbreviation "GMT".
# The following zone is used by tzcode functions like gmtime,
# which load the "UTC" file to handle seconds properly.
Zone Etc/UTC 0 - UTC
# Functions like gmtime load the "GMT" file to handle leap seconds properly.
# Vanguard section, which works with most .zi parsers.
#Zone GMT 0 - GMT
# Rearguard section, for TZUpdater 2.3.2 and earlier.
Zone Etc/GMT 0 - GMT
# The following link uses older naming conventions,
# but it belongs here, not in the file 'backward',
# as it is needed for tzcode releases through 2022a,
# where functions like gmtime load "GMT" instead of the "Etc/UTC".
# We want this to work even on installations that omit 'backward'.
Link Etc/GMT GMT
# End of rearguard section.
# Be consistent with POSIX TZ settings in the Zone names,
# even though this is the opposite of what many people expect.
# POSIX has positive signs west of Greenwich, but many people expect
# positive signs east of Greenwich. For example, TZ='Etc/GMT+4' uses
# the abbreviation "-04" and corresponds to 4 hours behind UT
# (i.e. west of Greenwich) even though many people would expect it to
# mean 4 hours ahead of UT (i.e. east of Greenwich).
# Earlier incarnations of this package were not POSIX-compliant,
# and had lines such as
# Zone GMT-12 -12 - GMT-1200
# We did not want things to change quietly if someone accustomed to the old
# way does a
# zic -l GMT-12
# so we moved the names into the Etc subdirectory.
# Also, the time zone abbreviations are now compatible with %z.
Zone Etc/GMT-14 14 - +14
Zone Etc/GMT-13 13 - +13
Zone Etc/GMT-12 12 - +12
Zone Etc/GMT-11 11 - +11
Zone Etc/GMT-10 10 - +10
Zone Etc/GMT-9 9 - +09
Zone Etc/GMT-8 8 - +08
Zone Etc/GMT-7 7 - +07
Zone Etc/GMT-6 6 - +06
Zone Etc/GMT-5 5 - +05
Zone Etc/GMT-4 4 - +04
Zone Etc/GMT-3 3 - +03
Zone Etc/GMT-2 2 - +02
Zone Etc/GMT-1 1 - +01
Zone Etc/GMT+1 -1 - -01
Zone Etc/GMT+2 -2 - -02
Zone Etc/GMT+3 -3 - -03
Zone Etc/GMT+4 -4 - -04
Zone Etc/GMT+5 -5 - -05
Zone Etc/GMT+6 -6 - -06
Zone Etc/GMT+7 -7 - -07
Zone Etc/GMT+8 -8 - -08
Zone Etc/GMT+9 -9 - -09
Zone Etc/GMT+10 -10 - -10
Zone Etc/GMT+11 -11 - -11
Zone Etc/GMT+12 -12 - -12
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff