Struct TimeZone
pub struct TimeZone { /* private fields */ }
dep_jiff
and alloc
only.Expand description
A representation of a time zone.
A time zone is a set of rules for determining the civil time, via an offset from UTC, in a particular geographic region. In many cases, the offset in a particular time zone can vary over the course of a year through transitions into and out of daylight saving time.
A TimeZone
can be one of three possible representations:
- An identifier from the IANA Time Zone Database and the rules associated with that identifier.
- A fixed offset where there are never any time zone transitions.
- A POSIX TZ string that specifies a standard offset and an optional daylight saving time offset along with a rule for when DST is in effect. The rule applies for every year. Since POSIX TZ strings cannot capture the full complexity of time zone rules, they generally should not be used.
The most practical and useful representation is an IANA time zone. Namely,
it enjoys broad support and its database is regularly updated to reflect
real changes in time zone rules throughout the world. On Unix systems,
the time zone database is typically found at /usr/share/zoneinfo
. For
more information on how Jiff interacts with The Time Zone Database, see
TimeZoneDatabase
.
In typical usage, users of Jiff shouldn’t need to reference a TimeZone
directly. Instead, there are convenience APIs on datetime types that accept
IANA time zone identifiers and do automatic database lookups for you. For
example, to convert a timestamp to a zone aware datetime:
use jiff::Timestamp;
let ts = Timestamp::from_second(1_456_789_123)?;
let zdt = ts.intz("America/New_York")?;
assert_eq!(zdt.to_string(), "2016-02-29T18:38:43-05:00[America/New_York]");
Or to convert a civil datetime to a zoned datetime corresponding to a precise instant in time:
use jiff::civil::date;
let dt = date(2024, 7, 15).at(21, 27, 0, 0);
let zdt = dt.intz("America/New_York")?;
assert_eq!(zdt.to_string(), "2024-07-15T21:27:00-04:00[America/New_York]");
Or even converted a zoned datetime from one time zone to another:
use jiff::civil::date;
let dt = date(2024, 7, 15).at(21, 27, 0, 0);
let zdt1 = dt.intz("America/New_York")?;
let zdt2 = zdt1.intz("Israel")?;
assert_eq!(zdt2.to_string(), "2024-07-16T04:27:00+03:00[Israel]");
§The system time zone
The system time zone can be retrieved via TimeZone::system
. If it
couldn’t be detected or if the tz-system
crate feature is not enabled,
then TimeZone::UTC
is returned. TimeZone::system
is what’s used
internally for retrieving the current zoned datetime via Zoned::now
.
While there is no platform independent way to detect your system’s
“default” time zone, Jiff employs best-effort heuristics to determine it.
(For example, by examining /etc/localtime
on Unix systems.) When the
heuristics fail, Jiff will emit a WARN
level log. It can be viewed by
installing a log
compatible logger, such as env_logger
.
§Custom time zones
At present, Jiff doesn’t provide any APIs for manually constructing a
custom time zone. However, TimeZone::tzif
is provided for reading
any valid TZif formatted data, as specified by RFC 8536. This provides
an interoperable way of utilizing custom time zone rules.
§A TimeZone
is immutable
Once a TimeZone
is created, it is immutable. That is, its underlying
time zone transition rules will never change. This is true for system time
zones or even if the IANA Time Zone Database it was loaded from changes on
disk. The only way such changes can be observed is by re-requesting the
TimeZone
from a TimeZoneDatabase
. (Or, in the case of the system time
zone, by calling TimeZone::system
.)
§Time zone equality
TimeZone
provides an imperfect notion of equality. That is, when two time
zones are equal, then it is guaranteed for them to have the same rules.
However, two time zones may compare unequal and yet still have the same
rules.
The equality semantics are as follows:
- Two fixed offset time zones are equal when their offsets are equal.
- Two POSIX time zones are equal when their original rule strings are byte-for-byte identical.
- Two IANA time zones are equal when their identifiers are equal and checksums of their rules are equal.
- In all other cases, time zones are unequal.
Time zone equality is, for example, used in APIs like Zoned::since
when asking for spans with calendar units. Namely, since days can be of
different lengths in different time zones, Zoned::since
will return an
error when the two zoned datetimes are in different time zones and when
the caller requests units greater than hours.
§Dealing with ambiguity
The principal job of a TimeZone
is to provide two different
transformations:
- A conversion from a
Timestamp
to a civil time (also known as local, naive or plain time). This conversion is always unambiguous. That is, there is always precisely one representation of civil time for any particular instant in time for a particular time zone. - A conversion from a
civil::DateTime
to an instant in time. This conversion is sometimes ambiguous in that a civil time might have either never appear on the clocks in a particular time zone (a gap), or in that the civil time may have been repeated on the clocks in a particular time zone (a fold). Typically, a transition to daylight saving time is a gap, while a transition out of daylight saving time is a fold.
The timestamp-to-civil time conversion is done via
TimeZone::to_datetime
, or its lower level counterpart,
TimeZone::to_offset
. The civil time-to-timestamp conversion is done
via one of the following routines:
TimeZone::to_zoned
conveniently returns aZoned
and automatically uses theDisambiguation::Compatible
strategy if the given civil datetime is ambiguous in the time zone.TimeZone::to_ambiguous_zoned
returns a potentially ambiguous zoned datetime,AmbiguousZoned
, and provides fine-grained control over how to resolve ambiguity, if it occurs.TimeZone::to_timestamp
is likeTimeZone::to_zoned
, but returns aTimestamp
instead.TimeZone::to_ambiguous_timestamp
is likeTimeZone::to_ambiguous_zoned
, but returns anAmbiguousTimestamp
instead.
Here is an example where we explore the different disambiguation strategies for a fold in time, where in this case, the 1 o’clock hour is repeated:
use jiff::{civil::date, tz::TimeZone};
let tz = TimeZone::get("America/New_York")?;
let dt = date(2024, 11, 3).at(1, 30, 0, 0);
// It's ambiguous, so asking for an unambiguous instant presents an error!
assert!(tz.to_ambiguous_zoned(dt).unambiguous().is_err());
// Gives you the earlier time in a fold, i.e., before DST ends:
assert_eq!(
tz.to_ambiguous_zoned(dt).earlier()?.to_string(),
"2024-11-03T01:30:00-04:00[America/New_York]",
);
// Gives you the later time in a fold, i.e., after DST ends.
// Notice the offset change from the previous example!
assert_eq!(
tz.to_ambiguous_zoned(dt).later()?.to_string(),
"2024-11-03T01:30:00-05:00[America/New_York]",
);
// "Just give me something reasonable"
assert_eq!(
tz.to_ambiguous_zoned(dt).compatible()?.to_string(),
"2024-11-03T01:30:00-04:00[America/New_York]",
);
Implementations§
§impl TimeZone
impl TimeZone
pub const UTC: TimeZone
pub const UTC: TimeZone
The UTC time zone.
The offset of this time is 0
and never has any transitions.
pub fn system() -> TimeZone
pub fn system() -> TimeZone
Returns the system configured time zone, if available.
If the system’s default time zone could not be determined, or if
the tz-system
crate feature is not enabled, then this returns
TimeZone::UTC
. A WARN
level log will also be emitted with a
message explaining why time zone detection failed. The fallback
to UTC is a practical trade-off, is what most other systems tend
to do and is also recommended by relevant standards such as
freedesktop.org.
Detection of a system’s default time zone is generally heuristic based and platform specific.
If callers need to know whether discovery of the system time zone
failed, then use TimeZone::try_system
.
§Platform behavior
This section is a “best effort” explanation of how the time zone is detected on supported platforms. The behavior is subject to change.
On all platforms, the TZ
environment variable overrides any other
heuristic, and provides a way for end users to set the time zone for
specific use cases. In general, Jiff respects the POSIX TZ rules.
Here are some examples:
TZ=America/New_York
for setting a time zone via an IANA Time Zone Database Identifier.TZ=/usr/share/zoneinfo/America/New_York
for setting a time zone by providing a file path to a TZif file directly.TZ=EST5EDT,M3.2.0,M11.1.0
for setting a time zone via a daylight saving time transition rule.
Otherwise, when TZ
isn’t set, then:
On Unix systems, this inspects /etc/localtime
. If it’s a symbolic
link to an entry in /usr/share/zoneinfo
, then the suffix is
considered an IANA Time Zone Database identifier. Otherwise,
/etc/localtime
is read as a TZif file directly.
On Windows, the system time zone is determined via
GetDynamicTimeZoneInformation
. The result is then mapped to an
IANA Time Zone Database identifier via Unicode’s
CLDR XML data.
pub fn try_system() -> Result<TimeZone, Error> ⓘ
pub fn try_system() -> Result<TimeZone, Error> ⓘ
Returns the system configured time zone, if available.
If the system’s default time zone could not be determined, or if the
tz-system
crate feature is not enabled, then this returns an error.
Detection of a system’s default time zone is generally heuristic based and platform specific.
Note that callers should generally prefer using TimeZone::system
.
If a system time zone could not be found, then it falls
back to TimeZone::UTC
automatically. This is often
what is recommended by relevant standards such as
freedesktop.org. Conversely, this routine
is useful if detection of a system’s default time zone is critical.
§Platform behavior
This section is a “best effort” explanation of how the time zone is detected on supported platforms. The behavior is subject to change.
On all platforms, the TZ
environment variable overrides any other
heuristic, and provides a way for end users to set the time zone for
specific use cases. In general, Jiff respects the POSIX TZ rules.
Here are some examples:
TZ=America/New_York
for setting a time zone via an IANA Time Zone Database Identifier.TZ=/usr/share/zoneinfo/America/New_York
for setting a time zone by providing a file path to a TZif file directly.TZ=EST5EDT,M3.2.0,M11.1.0
for setting a time zone via a daylight saving time transition rule.
Otherwise, when TZ
isn’t set, then:
On Unix systems, this inspects /etc/localtime
. If it’s a symbolic
link to an entry in /usr/share/zoneinfo
, then the suffix is
considered an IANA Time Zone Database identifier. Otherwise,
/etc/localtime
is read as a TZif file directly.
On Windows, the system time zone is determined via
GetDynamicTimeZoneInformation
. The result is then mapped to an
IANA Time Zone Database identifier via Unicode’s
CLDR XML data.
pub fn get(time_zone_name: &str) -> Result<TimeZone, Error> ⓘ
pub fn get(time_zone_name: &str) -> Result<TimeZone, Error> ⓘ
A convenience function for performing a time zone database lookup for
the given time zone identifier. It uses the default global time zone
database via tz::db()
.
§Errors
This returns an error if the given time zone identifier could not be
found in the default TimeZoneDatabase
.
§Example
use jiff::{tz::TimeZone, Timestamp};
let tz = TimeZone::get("Japan")?;
assert_eq!(
tz.to_datetime(Timestamp::UNIX_EPOCH).to_string(),
"1970-01-01T09:00:00",
);
pub fn fixed(offset: Offset) -> TimeZone
pub fn fixed(offset: Offset) -> TimeZone
Returns a time zone with a fixed offset.
A fixed offset will never have any transitions and won’t follow any
particular time zone rules. In general, one should avoid using fixed
offset time zones unless you have a specific need for them. Otherwise,
IANA time zones via TimeZone::get
should be preferred, as they
more accurately model the actual time zone transitions rules used in
practice.
§Example
use jiff::{tz::{self, TimeZone}, Timestamp};
let tz = TimeZone::fixed(tz::offset(10));
assert_eq!(
tz.to_datetime(Timestamp::UNIX_EPOCH).to_string(),
"1970-01-01T10:00:00",
);
pub fn posix(posix_tz_string: &str) -> Result<TimeZone, Error> ⓘ
pub fn posix(posix_tz_string: &str) -> Result<TimeZone, Error> ⓘ
Creates a time zone from a POSIX TZ rule string.
A POSIX time zone provides a way to tersely define a single daylight saving time transition rule (or none at all) that applies for all years.
Users should avoid using this kind of time zone unless there is a specific need for it. Namely, POSIX time zones cannot capture the full complexity of time zone transition rules in the real world. (See the example below.)
§Errors
This returns an error if the given POSIX time zone string is invalid.
§Example
This example demonstrates how a POSIX time zone may be historically inaccurate:
use jiff::{civil::date, tz::TimeZone};
// The tzdb entry for America/New_York.
let iana = TimeZone::get("America/New_York")?;
// The POSIX TZ string for New York DST that went into effect in 2007.
let posix = TimeZone::posix("EST5EDT,M3.2.0,M11.1.0")?;
// New York entered DST on April 2, 2006 at 2am:
let dt = date(2006, 4, 2).at(2, 0, 0, 0);
// The IANA tzdb entry correctly reports it as ambiguous:
assert!(iana.to_ambiguous_timestamp(dt).is_ambiguous());
// But the POSIX time zone does not:
assert!(!posix.to_ambiguous_timestamp(dt).is_ambiguous());
pub fn tzif(name: &str, data: &[u8]) -> Result<TimeZone, Error> ⓘ
pub fn tzif(name: &str, data: &[u8]) -> Result<TimeZone, Error> ⓘ
Creates a time zone from TZif binary data, whose format is specified in RFC 8536. All versions of TZif (up through version 4) are supported.
This constructor is typically not used, and instead, one should rely
on time zone lookups via time zone identifiers with routines like
TimeZone::get
. However, this constructor does provide one way
of using custom time zones with Jiff.
The name given should be a IANA time zone database identifier.
§Errors
This returns an error if the given data was not recognized as valid TZif.
pub fn iana_name(&self) -> Option<&str> ⓘ
pub fn iana_name(&self) -> Option<&str> ⓘ
When this time zone was loaded from an IANA time zone database entry, then this returns the canonicalized name for that time zone.
§Example
use jiff::tz::TimeZone;
let tz = TimeZone::get("america/NEW_YORK")?;
assert_eq!(tz.iana_name(), Some("America/New_York"));
pub fn to_datetime(&self, timestamp: Timestamp) -> DateTime
pub fn to_datetime(&self, timestamp: Timestamp) -> DateTime
Returns the civil datetime corresponding to the given timestamp in this time zone.
This operation is always unambiguous. That is, for any instant in time
supported by Jiff (that is, a Timestamp
), there is always precisely
one civil datetime corresponding to that instant.
Note that this is considered a lower level routine. Consider working
with zoned datetimes instead, and use Zoned::datetime
to get its
civil time if necessary.
§Example
use jiff::{tz::TimeZone, Timestamp};
let tz = TimeZone::get("Europe/Rome")?;
assert_eq!(
tz.to_datetime(Timestamp::UNIX_EPOCH).to_string(),
"1970-01-01T01:00:00",
);
As mentioned above, consider using Zoned
instead:
use jiff::{tz::TimeZone, Timestamp};
let zdt = Timestamp::UNIX_EPOCH.intz("Europe/Rome")?;
assert_eq!(zdt.datetime().to_string(), "1970-01-01T01:00:00");
pub fn to_offset(&self, _timestamp: Timestamp) -> (Offset, Dst, &str) ⓘ
pub fn to_offset(&self, _timestamp: Timestamp) -> (Offset, Dst, &str) ⓘ
Returns the offset corresponding to the given timestamp in this time zone.
This operation is always unambiguous. That is, for any instant in time
supported by Jiff (that is, a Timestamp
), there is always precisely
one offset corresponding to that instant.
Given an offset, one can use APIs like Offset::to_datetime
to
create a civil datetime from a timestamp.
This also returns whether this timestamp is considered to be in “daylight saving time,” as well as the abbreviation for the time zone at this time.
§Example
use jiff::{tz::{self, Dst, TimeZone}, Timestamp};
let tz = TimeZone::get("America/New_York")?;
// A timestamp in DST in New York.
let ts = Timestamp::from_second(1_720_493_204)?;
let (offset, dst, abbrev) = tz.to_offset(ts);
assert_eq!(offset, tz::offset(-4));
assert_eq!(dst, Dst::Yes);
assert_eq!(abbrev, "EDT");
assert_eq!(offset.to_datetime(ts).to_string(), "2024-07-08T22:46:44");
// A timestamp *not* in DST in New York.
let ts = Timestamp::from_second(1_704_941_204)?;
let (offset, dst, abbrev) = tz.to_offset(ts);
assert_eq!(offset, tz::offset(-5));
assert_eq!(dst, Dst::No);
assert_eq!(abbrev, "EST");
assert_eq!(offset.to_datetime(ts).to_string(), "2024-01-10T21:46:44");
pub fn to_fixed_offset(&self) -> Result<Offset, Error> ⓘ
pub fn to_fixed_offset(&self) -> Result<Offset, Error> ⓘ
If this time zone is a fixed offset, then this returns the offset. If this time zone is not a fixed offset, then an error is returned.
If you just need an offset for a given timestamp, then you can use
TimeZone::to_offset
. Or, if you need an offset for a civil
datetime, then you can use TimeZone::to_ambiguous_timestamp
or
TimeZone::to_ambiguous_zoned
, although the result may be ambiguous.
Generally, this routine is useful when you need to know whether the time zone is fixed, and you want to get the offset without having to specify a timestamp. This is sometimes required for interoperating with other datetime systems that need to distinguish between time zones that are fixed and time zones that are based on rules such as those found in the IANA time zone database.
§Example
use jiff::tz::{Offset, TimeZone};
let tz = TimeZone::get("America/New_York")?;
// A named time zone is not a fixed offset
// and so cannot be converted to an offset
// without a timestamp or civil datetime.
assert_eq!(
tz.to_fixed_offset().unwrap_err().to_string(),
"cannot convert non-fixed IANA time zone \
to offset without timestamp or civil datetime",
);
let tz = TimeZone::UTC;
// UTC is a fixed offset and so can be converted
// without a timestamp.
assert_eq!(tz.to_fixed_offset()?, Offset::UTC);
// And of course, creating a time zone from a
// fixed offset results in a fixed offset time
// zone too:
let tz = TimeZone::fixed(jiff::tz::offset(-10));
assert_eq!(tz.to_fixed_offset()?, jiff::tz::offset(-10));
pub fn to_zoned(&self, dt: DateTime) -> Result<Zoned, Error> ⓘ
pub fn to_zoned(&self, dt: DateTime) -> Result<Zoned, Error> ⓘ
Converts a civil datetime to a Zoned
in this time zone.
The given civil datetime may be ambiguous in this time zone. A civil datetime is ambiguous when either of the following occurs:
- When the civil datetime falls into a “gap.” That is, when there is a jump forward in time where a span of time does not appear on the clocks in this time zone. This typically manifests as a 1 hour jump forward into daylight saving time.
- When the civil datetime falls into a “fold.” That is, when there is a jump backward in time where a span of time is repeated on the clocks in this time zone. This typically manifests as a 1 hour jump backward out of daylight saving time.
This routine automatically resolves both of the above ambiguities via
the Disambiguation::Compatible
strategy. That in, the case of a
gap, the time after the gap is used. In the case of a fold, the first
repetition of the clock time is used.
§Example
This example shows how disambiguation works:
use jiff::{civil::date, tz::TimeZone};
let tz = TimeZone::get("America/New_York")?;
// This demonstrates disambiguation behavior for a gap.
let zdt = tz.to_zoned(date(2024, 3, 10).at(2, 30, 0, 0))?;
assert_eq!(zdt.to_string(), "2024-03-10T03:30:00-04:00[America/New_York]");
// This demonstrates disambiguation behavior for a fold.
// Notice the offset: the -04 corresponds to the time while
// still in DST. The second repetition of the 1 o'clock hour
// occurs outside of DST, in "standard" time, with the offset -5.
let zdt = tz.to_zoned(date(2024, 11, 3).at(1, 30, 0, 0))?;
assert_eq!(zdt.to_string(), "2024-11-03T01:30:00-04:00[America/New_York]");
pub fn to_ambiguous_zoned(&self, dt: DateTime) -> AmbiguousZoned
pub fn to_ambiguous_zoned(&self, dt: DateTime) -> AmbiguousZoned
Converts a civil datetime to a possibly ambiguous zoned datetime in this time zone.
The given civil datetime may be ambiguous in this time zone. A civil datetime is ambiguous when either of the following occurs:
- When the civil datetime falls into a “gap.” That is, when there is a jump forward in time where a span of time does not appear on the clocks in this time zone. This typically manifests as a 1 hour jump forward into daylight saving time.
- When the civil datetime falls into a “fold.” That is, when there is a jump backward in time where a span of time is repeated on the clocks in this time zone. This typically manifests as a 1 hour jump backward out of daylight saving time.
Unlike TimeZone::to_zoned
, this method does not do any automatic
disambiguation. Instead, callers are expected to use the methods on
AmbiguousZoned
to resolve any ambiguity, if it occurs.
§Example
This example shows how to return an error when the civil datetime given is ambiguous:
use jiff::{civil::date, tz::TimeZone};
let tz = TimeZone::get("America/New_York")?;
// This is not ambiguous:
let dt = date(2024, 3, 10).at(1, 0, 0, 0);
assert_eq!(
tz.to_ambiguous_zoned(dt).unambiguous()?.to_string(),
"2024-03-10T01:00:00-05:00[America/New_York]",
);
// But this is a gap, and thus ambiguous! So an error is returned.
let dt = date(2024, 3, 10).at(2, 0, 0, 0);
assert!(tz.to_ambiguous_zoned(dt).unambiguous().is_err());
// And so is this, because it's a fold.
let dt = date(2024, 11, 3).at(1, 0, 0, 0);
assert!(tz.to_ambiguous_zoned(dt).unambiguous().is_err());
pub fn into_ambiguous_zoned(self, dt: DateTime) -> AmbiguousZoned
pub fn into_ambiguous_zoned(self, dt: DateTime) -> AmbiguousZoned
Converts a civil datetime to a possibly ambiguous zoned datetime in
this time zone, and does so by assuming ownership of this TimeZone
.
This is identical to TimeZone::to_ambiguous_zoned
, but it avoids
a TimeZone::clone()
call. (Which are cheap, but not completely free.)
§Example
This example shows how to create a Zoned
value from a TimeZone
and a DateTime
without cloning the TimeZone
:
use jiff::{civil::date, tz::TimeZone};
let tz = TimeZone::get("America/New_York")?;
let dt = date(2024, 3, 10).at(1, 0, 0, 0);
assert_eq!(
tz.into_ambiguous_zoned(dt).unambiguous()?.to_string(),
"2024-03-10T01:00:00-05:00[America/New_York]",
);
pub fn to_timestamp(&self, dt: DateTime) -> Result<Timestamp, Error> ⓘ
pub fn to_timestamp(&self, dt: DateTime) -> Result<Timestamp, Error> ⓘ
Converts a civil datetime to a Timestamp
in this time zone.
The given civil datetime may be ambiguous in this time zone. A civil datetime is ambiguous when either of the following occurs:
- When the civil datetime falls into a “gap.” That is, when there is a jump forward in time where a span of time does not appear on the clocks in this time zone. This typically manifests as a 1 hour jump forward into daylight saving time.
- When the civil datetime falls into a “fold.” That is, when there is a jump backward in time where a span of time is repeated on the clocks in this time zone. This typically manifests as a 1 hour jump backward out of daylight saving time.
This routine automatically resolves both of the above ambiguities via
the Disambiguation::Compatible
strategy. That in, the case of a
gap, the time after the gap is used. In the case of a fold, the first
repetition of the clock time is used.
This routine is identical to TimeZone::to_zoned
, except it returns
a Timestamp
instead of a zoned datetime. The benefit of this
method is that it never requires cloning or consuming ownership of a
TimeZone
, and it doesn’t require construction of Zoned
which has
a small but non-zero cost. (This is partially because a Zoned
value
contains a TimeZone
, but of course, a Timestamp
does not.)
§Example
This example shows how disambiguation works:
use jiff::{civil::date, tz::TimeZone};
let tz = TimeZone::get("America/New_York")?;
// This demonstrates disambiguation behavior for a gap.
let ts = tz.to_timestamp(date(2024, 3, 10).at(2, 30, 0, 0))?;
assert_eq!(ts.to_string(), "2024-03-10T07:30:00Z");
// This demonstrates disambiguation behavior for a fold.
// Notice the offset: the -04 corresponds to the time while
// still in DST. The second repetition of the 1 o'clock hour
// occurs outside of DST, in "standard" time, with the offset -5.
let ts = tz.to_timestamp(date(2024, 11, 3).at(1, 30, 0, 0))?;
assert_eq!(ts.to_string(), "2024-11-03T05:30:00Z");
pub fn to_ambiguous_timestamp(&self, dt: DateTime) -> AmbiguousTimestamp
pub fn to_ambiguous_timestamp(&self, dt: DateTime) -> AmbiguousTimestamp
Converts a civil datetime to a possibly ambiguous timestamp in this time zone.
The given civil datetime may be ambiguous in this time zone. A civil datetime is ambiguous when either of the following occurs:
- When the civil datetime falls into a “gap.” That is, when there is a jump forward in time where a span of time does not appear on the clocks in this time zone. This typically manifests as a 1 hour jump forward into daylight saving time.
- When the civil datetime falls into a “fold.” That is, when there is a jump backward in time where a span of time is repeated on the clocks in this time zone. This typically manifests as a 1 hour jump backward out of daylight saving time.
Unlike TimeZone::to_timestamp
, this method does not do any
automatic disambiguation. Instead, callers are expected to use the
methods on AmbiguousTimestamp
to resolve any ambiguity, if it
occurs.
This routine is identical to TimeZone::to_ambiguous_zoned
, except
it returns an AmbiguousTimestamp
instead of a AmbiguousZoned
. The
benefit of this method is that it never requires cloning or consuming
ownership of a TimeZone
, and it doesn’t require construction of
Zoned
which has a small but non-zero cost. (This is partially because
a Zoned
value contains a TimeZone
, but of course, a Timestamp
does not.)
§Example
This example shows how to return an error when the civil datetime given is ambiguous:
use jiff::{civil::date, tz::TimeZone};
let tz = TimeZone::get("America/New_York")?;
// This is not ambiguous:
let dt = date(2024, 3, 10).at(1, 0, 0, 0);
assert_eq!(
tz.to_ambiguous_timestamp(dt).unambiguous()?.to_string(),
"2024-03-10T06:00:00Z",
);
// But this is a gap, and thus ambiguous! So an error is returned.
let dt = date(2024, 3, 10).at(2, 0, 0, 0);
assert!(tz.to_ambiguous_timestamp(dt).unambiguous().is_err());
// And so is this, because it's a fold.
let dt = date(2024, 11, 3).at(1, 0, 0, 0);
assert!(tz.to_ambiguous_timestamp(dt).unambiguous().is_err());
pub fn preceding<'t>(
&'t self,
timestamp: Timestamp,
) -> TimeZonePrecedingTransitions<'t> ⓘ
pub fn preceding<'t>( &'t self, timestamp: Timestamp, ) -> TimeZonePrecedingTransitions<'t> ⓘ
Returns an iterator of time zone transitions preceding the given
timestamp. The iterator returned yields TimeZoneTransition
elements.
The order of the iterator returned moves backward through time. If there is a previous transition, then the timestamp of that transition is guaranteed to be strictly less than the timestamp given.
This is a low level API that you generally shouldn’t need. It’s useful in cases where you need to know something about the specific instants at which time zone transitions occur. For example, an embedded device might need to be explicitly programmed with daylight saving time transitions. APIs like this enable callers to explore those transitions.
A time zone transition refers to a specific point in time when the offset from UTC for a particular geographical region changes. This is usually a result of daylight saving time, but it can also occur when a geographic region changes its permanent offset from UTC.
The iterator returned is not guaranteed to yield any elements. For example, this occurs with a fixed offset time zone. Logically, it would also be possible for the iterator to be infinite, except that eventually the timestamp would overflow Jiff’s minimum timestamp value, at which point, iteration stops.
§Example: time since the previous transition
This example shows how much time has passed since the previous time zone transition:
use jiff::{Unit, Zoned};
let now: Zoned = "2024-12-31 18:25-05[US/Eastern]".parse()?;
let trans = now.time_zone().preceding(now.timestamp()).next().unwrap();
let prev_at = trans.timestamp().to_zoned(now.time_zone().clone());
let span = now.since((Unit::Year, &prev_at))?;
assert_eq!(format!("{span:#}"), "1mo 27d 17h 25m");
§Example: show the 5 previous time zone transitions
This shows how to find the 5 preceding time zone transitions (from a particular datetime) for a particular time zone:
use jiff::{tz::offset, Zoned};
let now: Zoned = "2024-12-31 18:25-05[US/Eastern]".parse()?;
let transitions = now
.time_zone()
.preceding(now.timestamp())
.take(5)
.map(|t| (
t.timestamp().to_zoned(now.time_zone().clone()),
t.offset(),
t.abbreviation(),
))
.collect::<Vec<_>>();
assert_eq!(transitions, vec![
("2024-11-03 01:00-05[US/Eastern]".parse()?, offset(-5), "EST"),
("2024-03-10 03:00-04[US/Eastern]".parse()?, offset(-4), "EDT"),
("2023-11-05 01:00-05[US/Eastern]".parse()?, offset(-5), "EST"),
("2023-03-12 03:00-04[US/Eastern]".parse()?, offset(-4), "EDT"),
("2022-11-06 01:00-05[US/Eastern]".parse()?, offset(-5), "EST"),
]);
pub fn following<'t>(
&'t self,
timestamp: Timestamp,
) -> TimeZoneFollowingTransitions<'t> ⓘ
pub fn following<'t>( &'t self, timestamp: Timestamp, ) -> TimeZoneFollowingTransitions<'t> ⓘ
Returns an iterator of time zone transitions following the given
timestamp. The iterator returned yields TimeZoneTransition
elements.
The order of the iterator returned moves forward through time. If there is a following transition, then the timestamp of that transition is guaranteed to be strictly greater than the timestamp given.
This is a low level API that you generally shouldn’t need. It’s useful in cases where you need to know something about the specific instants at which time zone transitions occur. For example, an embedded device might need to be explicitly programmed with daylight saving time transitions. APIs like this enable callers to explore those transitions.
A time zone transition refers to a specific point in time when the offset from UTC for a particular geographical region changes. This is usually a result of daylight saving time, but it can also occur when a geographic region changes its permanent offset from UTC.
The iterator returned is not guaranteed to yield any elements. For example, this occurs with a fixed offset time zone. Logically, it would also be possible for the iterator to be infinite, except that eventually the timestamp would overflow Jiff’s maximum timestamp value, at which point, iteration stops.
§Example: time until the next transition
This example shows how much time is left until the next time zone transition:
use jiff::{Unit, Zoned};
let now: Zoned = "2024-12-31 18:25-05[US/Eastern]".parse()?;
let trans = now.time_zone().following(now.timestamp()).next().unwrap();
let next_at = trans.timestamp().to_zoned(now.time_zone().clone());
let span = now.until((Unit::Year, &next_at))?;
assert_eq!(format!("{span:#}"), "2mo 8d 7h 35m");
§Example: show the 5 next time zone transitions
This shows how to find the 5 following time zone transitions (from a particular datetime) for a particular time zone:
use jiff::{tz::offset, Zoned};
let now: Zoned = "2024-12-31 18:25-05[US/Eastern]".parse()?;
let transitions = now
.time_zone()
.following(now.timestamp())
.take(5)
.map(|t| (
t.timestamp().to_zoned(now.time_zone().clone()),
t.offset(),
t.abbreviation(),
))
.collect::<Vec<_>>();
assert_eq!(transitions, vec![
("2025-03-09 03:00-04[US/Eastern]".parse()?, offset(-4), "EDT"),
("2025-11-02 01:00-05[US/Eastern]".parse()?, offset(-5), "EST"),
("2026-03-08 03:00-04[US/Eastern]".parse()?, offset(-4), "EDT"),
("2026-11-01 01:00-05[US/Eastern]".parse()?, offset(-5), "EST"),
("2027-03-14 03:00-04[US/Eastern]".parse()?, offset(-4), "EDT"),
]);
Trait Implementations§
impl Eq for TimeZone
impl StructuralPartialEq for TimeZone
Auto Trait Implementations§
impl Freeze for TimeZone
impl RefUnwindSafe for TimeZone
impl Send for TimeZone
impl Sync for TimeZone
impl Unpin for TimeZone
impl UnwindSafe for TimeZone
Blanket Implementations§
§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
§type ArchivedMetadata = ()
type ArchivedMetadata = ()
§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> ByteSized for T
impl<T> ByteSized for T
Source§const BYTE_ALIGN: usize = _
const BYTE_ALIGN: usize = _
Source§fn byte_align(&self) -> usize ⓘ
fn byte_align(&self) -> usize ⓘ
Source§fn ptr_size_ratio(&self) -> [usize; 2]
fn ptr_size_ratio(&self) -> [usize; 2]
Source§impl<T, R> Chain<R> for Twhere
T: ?Sized,
impl<T, R> Chain<R> for Twhere
T: ?Sized,
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.Source§impl<T> ExtAny for T
impl<T> ExtAny for T
Source§fn as_any_mut(&mut self) -> &mut dyn Anywhere
Self: Sized,
fn as_any_mut(&mut self) -> &mut dyn Anywhere
Self: Sized,
Source§impl<T> ExtMem for Twhere
T: ?Sized,
impl<T> ExtMem for Twhere
T: ?Sized,
Source§const NEEDS_DROP: bool = _
const NEEDS_DROP: bool = _
Source§fn mem_align_of_val(&self) -> usize ⓘ
fn mem_align_of_val(&self) -> usize ⓘ
Source§fn mem_size_of_val(&self) -> usize ⓘ
fn mem_size_of_val(&self) -> usize ⓘ
Source§fn mem_needs_drop(&self) -> bool
fn mem_needs_drop(&self) -> bool
true
if dropping values of this type matters. Read moreSource§fn mem_forget(self)where
Self: Sized,
fn mem_forget(self)where
Self: Sized,
self
without running its destructor. Read moreSource§fn mem_replace(&mut self, other: Self) -> Selfwhere
Self: Sized,
fn mem_replace(&mut self, other: Self) -> Selfwhere
Self: Sized,
Source§unsafe fn mem_zeroed<T>() -> T
unsafe fn mem_zeroed<T>() -> T
unsafe_layout
only.T
represented by the all-zero byte-pattern. Read moreSource§unsafe fn mem_transmute_copy<Src, Dst>(src: &Src) -> Dst
unsafe fn mem_transmute_copy<Src, Dst>(src: &Src) -> Dst
unsafe_layout
only.T
represented by the all-zero byte-pattern. Read moreSource§fn mem_as_bytes(&self) -> &[u8] ⓘ
fn mem_as_bytes(&self) -> &[u8] ⓘ
unsafe_slice
only.§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Hook for T
impl<T> Hook for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError> ⓘ
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError> ⓘ
§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out
indicating that a T
is niched.