Struct TimeZone

#[repr(align(8))]
pub struct TimeZone { pub std_abbrev: Abbreviation, pub std_offset: Offset, pub dst: Option<Dst> }

A representation of a POSIX time zone transition rule.

POSIX time zones are limited in what they can express. Notably, they can't handle historic time zone transitions. They generally can only handle present rules.

Note that the internals of this type are completely exposed to make writing static data with these types easier.

On "reasonable" POSIX time zones

Jiff only supports "reasonable" POSIX time zones. A "reasonable" POSIX time zone is a POSIX time zone that has a DST transition rule when it has a DST time zone abbreviation. Without the transition rule, it isn't possible to know when DST starts and stops.

POSIX technically allows a DST time zone abbreviation without a transition rule, but the behavior is literally unspecified. So Jiff just rejects them.

Note that if you're confused as to why Jiff accepts TZ=EST5EDT (where EST5EDT is an example of an unreasonable POSIX time zone), that's because Jiff rejects EST5EDT and instead attempts to use it as an IANA time zone identifier. And indeed, the IANA Time Zone Database contains an entry for EST5EDT (presumably for legacy reasons).

Also, we expect TZ strings parsed from IANA v2+ formatted tzfiles to also be reasonable or parsing fails. This also seems to be consistent with the GNU C Library's treatment of the TZ variable: it only documents support for reasonable POSIX time zone strings.

Note that a V2 TZ string is precisely identical to a POSIX TZ environment variable string. A V3 TZ string however supports signed DST transition times, and hours in the range 0..=167. The V2 and V3 here reference how TZ strings are defined in the TZif format specified by RFC 9636. V2 is the original version of it straight from POSIX, where as V3+ corresponds to an extension added to V3 (and newer versions) of the TZif format. V3 is a superset of V2, so in practice, Jiff just permits V3 everywhere.

Example

use jiff_core::{tz::{Offset, posix::TimeZone}, Timestamp};

let tz = TimeZone::parse("EST5EDT,M3.2.0,M11.1.0").unwrap();

let ts = Timestamp::from_second(1783100574).unwrap();
let offset = tz.to_offset(ts);
assert_eq!(offset, Offset::from_seconds(-4 * 60 * 60).unwrap());

// Around 6 months later, we should be out of DST.
let ts = Timestamp::from_second(ts.as_second() + 6 * 30 * 86400).unwrap();
let offset = tz.to_offset(ts);
assert_eq!(offset, Offset::from_seconds(-5 * 60 * 60).unwrap());

Fields

std_abbrev: Abbreviation

The abbreviation for standard time.

std_offset: Offset

The offset for standard time.

dst: Option<Dst>

Whether there is any daylight saving time for this POSIX time zone.

Implementations

impl TimeZone

fn to_offset(&self, timestamp: Timestamp) -> Offset

Returns the appropriate time zone offset to use for the given timestamp.

If you need information like whether the offset is in DST or not, or the time zone abbreviation, then use TimeZone::to_offset_info. But that API may be more expensive to use, so only use it if you need the additional data.

fn to_offset_info(&self, timestamp: Timestamp) -> OffsetInfo

Returns the appropriate time zone offset to use for the given timestamp.

This also includes whether the offset returned should be considered to be "DST" or not, along with the time zone abbreviation (e.g., EST for standard time in New York, and EDT for DST in New York).

fn to_ambiguous_timestamp(&self, dt: DateTime) -> AmbiguousTimestamp

Returns a possibly ambiguous timestamp for the given civil datetime.

The given datetime should correspond to the "wall" clock time of what humans use to tell time for this time zone.

Note that "ambiguous timestamp" is represented by the possible selection of offsets that could be applied to the given datetime. In general, it is only ambiguous around transitions to-and-from DST. The ambiguity can arise as a "fold" (when a particular wall clock time is repeated) or as a "gap" (when a particular wall clock time is skipped entirely).

fn previous_transition(&self, timestamp: Timestamp) -> Option<Transition>

Returns the timestamp of the most recent time zone transition prior to the timestamp given. If one doesn't exist, None is returned.

fn next_transition(&self, timestamp: Timestamp) -> Option<Transition>

Returns the timestamp of the soonest time zone transition after the timestamp given. If one doesn't exist, None is returned.

impl TimeZone

fn parse<B: AsRef<[u8]>>(bytes: B) -> Result<TimeZone, ParseError>

Parse a POSIX TZ environment variable, assuming it's a rule and not an implementation defined value, from the given byte string.

Errors

This returns an error if the given byte string is not a valid POSIX time zone transition rule.

This also returns an error if, after parsing the POSIX time zone transition rule, there are still bytes remaining in the string given.

fn parse_prefix<'b, B: AsRef<[u8]> + ?Sized>(bytes: &'b B) -> Result<(TimeZone, usize), ParseError>

Like TimeZone::parse, but parses a prefix of the input given. In addition to returning a TimeZone, this also returns the offset into bytes pointing at the beginning of any remaining unparsed input.

Errors

This returns an error if the given byte string is not a valid POSIX time zone transition rule.

Trait Implementations

impl Clone for TimeZone

fn clone(&self) -> TimeZone

impl Debug for TimeZone

fn fmt(&self, f: &mut Formatter<'_>) -> Result

impl Eq for TimeZone

impl PartialEq for TimeZone

fn eq(&self, other: &TimeZone) -> bool

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 UnsafeUnpin for TimeZone

impl UnwindSafe for TimeZone

Blanket Implementations

impl<T> Any for TimeZone where T: 'static + ?Sized,

fn type_id(&self) -> TypeId

impl<T> Borrow<T> for TimeZone where T: ?Sized,

fn borrow(&self) -> &T

impl<T> BorrowMut<T> for TimeZone where T: ?Sized,

fn borrow_mut(&mut self) -> &mut T

impl<T> CloneToUninit for TimeZone where T: Clone,

unsafe fn clone_to_uninit(&self, dest: *mut u8)

impl<T> From<T> for TimeZone

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> ToOwned for TimeZone where T: Clone,

type Owned = T;
fn to_owned(&self) -> T
fn clone_into(&self, target: &mut T)

impl<T, U> Into<U> for TimeZone where U: From<T>,

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

impl<T, U> TryFrom<U> for TimeZone where U: Into<T>,

type Error = Infallible;
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

impl<T, U> TryInto<U> for TimeZone where U: TryFrom<T>,

type Error = <U as TryFrom<T>>::Error;
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>