Chrono-TZ is a library that provides implementors of the TimeZone trait for chrono. The
impls are generated by a build script using the IANA database and parse-zoneinfo.
Documentation is hosted on docs.rs
Create a time in one timezone and convert it to UTC
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
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.
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.
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
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
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
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
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");To use this library without depending on the Rust standard library, put this
in your Cargo.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:
[profile.dev]
opt-level = 2
lto = true
[profile.release]
lto = trueOtherwise, the additional binary size added by this library may overflow available program space and trigger a linker error.
Chrono-tz by default generates timezone data for all entries in the IANA database from the years 1800 to 2100. If you are
only interested in a subset, you can reduce the size of the generated database in two ways:
- Select only the timezone names you care about.
- Limit the generated transition data to a bounded timestamp range.
Both options are controlled via environment variables and should be set in your top-level build.
Enable the filter-by-regex feature and set CHRONO_TZ_TIMEZONE_FILTER to a regular expression matching the timezone names you want:
CHRONO_TZ_TIMEZONE_FILTER="(Europe/London|US/.*)" cargo buildThis 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.
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".
If you only care about timezone behavior within a bounded period, enable filter-by-range and set
CHRONO_TZ_TIME_RANGE to a Rust-style timestamp range in Unix seconds:
# Only keep data from 2020-01-01 to 2030-01-01 UTC (Exclusive)
CHRONO_TZ_TIME_RANGE="1577836800..1893456000" cargo buildYou may also omit the start or end of the range to only keep data before or after a certain time.
# Only keep data from 2020-01-01 UTC onwards
CHRONO_TZ_TIME_RANGE="1577836800.." cargo build
# Only keep data up to 2020-01-01 UTC
CHRONO_TZ_TIME_RANGE="..1577836800" cargo buildFor timestamps outside the configured range, chrono-tz will use the time zone in effect at the nearest point within the configured range. For example, if your range ends on January 1, 2030, then a date in July 2035 will use which ever was in effect on January 1, 2030.
chrono-tz uses git submodules, so in order to build locally you will need to
run git submodule init and git submodule update.
- Handle leap seconds
- Handle Julian to Gregorian calendar transitions
- Load tzdata always from latest version
- Dynamic tzdata loading