Enum TransitionKind

pub enum TransitionKind

The kind of a transition.

This is used when trying to determine the offset for a local datetime. It indicates how the corresponding civil datetimes in civil_starts and civil_ends should be interpreted. That is, there are three possible cases:

  1. The offset of this transition is equivalent to the offset of the previous transition. That means there are no ambiguous civil datetimes between the transitions. This can occur, e.g., when the time zone abbreviation changes.
  2. The offset of the transition is greater than the offset of the previous transition. That means there is a "gap" in local time between the transitions. This typically corresponds to entering daylight saving time. It is usually, but not always, 1 hour.
  3. The offset of the transition is less than the offset of the previous transition. That means there is a "fold" in local time where time is repeated. This typically corresponds to leaving daylight saving time. It is usually, but not always, 1 hour.

More explanation

This, when combined with civil_starts and civil_ends in Transitions, explicitly represents ambiguous wall clock times that occur at the boundaries of transitions.

The start of the wall clock time is always the earlier possible wall clock time that could occur with this transition's corresponding offset. For a gap, it's the previous transition's offset. For a fold, it's the current transition's offset.

For example, DST for America/New_York began on 2024-03-10T07:00:00+00. The offset prior to this instant in time is -05, corresponding to standard time (EST). Thus, in wall clock time, DST began at 2024-03-10T02:00:00. And since this is a DST transition that jumps ahead an hour, the start of DST also corresponds to the start of a gap. That is, the times 02:00:00 through 02:59:59 never appear on a clock for this hour. The question is thus: which offset should we apply to 02:00:00? We could apply the offset from the earlier transition -05 and get 2024-03-10T01:00:00-05 (that's 2024-03-10T06:00:00+00), or we could apply the offset from the later transition -04 and get 2024-03-10T03:00:00-04 (that's 2024-03-10T07:00:00+00).

So in the above, we would have a Gap variant where start (inclusive) is 2024-03-10T02:00:00 and end (exclusive) is 2024-03-10T03:00:00.

The fold case is the same idea, but where the same time is repeated. For example, in America/New_York, standard time began on 2024-11-03T06:00:00+00. The offset prior to this instant in time is -04, corresponding to DST (EDT). Thus, in wall clock time, DST ended at 2024-11-03T02:00:00. However, since this is a fold, the actual set of ambiguous times begins at 2024-11-03T01:00:00 and ends at 2024-11-03T01:59:59.999999999. That is, the wall clock time 2024-11-03T02:00:00 is unambiguous.

So in the fold case above, we would have a Fold variant where start (inclusive) is 2024-11-03T01:00:00 and end (exclusive) is 2024-11-03T02:00:00.

Since this gets bundled in with the sorted sequence of transitions, we'll use the "start" time in all three cases as our target of binary search. Once we land on a transition, we'll know our given wall clock time is greater than or equal to its start wall clock time. At that point, to determine if there is ambiguity, we merely need to determine if the given wall clock time is less than the corresponding end time. If it is, then it falls in a gap or fold. Otherwise, it's unambiguous.

Note that we could compute these datetime values while searching for the correct transition, but there's a fair bit of math involved in going between timestamps (which is what TZif gives us) and calendar datetimes (which is what we're given as input). It is also necessary that we offset the timestamp given in TZif at some point, since it is in UTC and the datetime given is in wall clock time. So I decided it would be worth pre-computing what we need in terms of what the input is. This way, we don't need to do any conversions, or indeed, any arithmetic at all, for time zone lookups. We could store these as transitions, but then the input datetime would need to be converted to a timestamp before searching the transitions.

Variants

Unambiguous

This transition cannot possibly lead to an unambiguous offset because its offset is equivalent to the offset of the previous transition.

Has an entry in civil_starts, but corresponding entry in civil_ends is always zeroes (i.e., meaningless).

Gap

This occurs when this transition's offset is strictly greater than the previous transition's offset. This effectively results in a "gap" of time equal to the difference in the offsets between the two transitions.

Has an entry in civil_starts for when the gap starts (inclusive) in local time. Also has an entry in civil_ends for when the fold ends (exclusive) in local time.

Fold

This occurs when this transition's offset is strictly less than the previous transition's offset. This results in a "fold" of time where the two transitions have an overlap where it is ambiguous which one applies given a wall clock time. In effect, a span of time equal to the difference in the offsets is repeated.

Has an entry in civil_starts for when the fold starts (inclusive) in local time. Also has an entry in civil_ends for when the fold ends (exclusive) in local time.

Trait Implementations

impl Clone for TransitionKind

fn clone(&self) -> TransitionKind

impl Copy for TransitionKind

impl Debug for TransitionKind

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

Auto Trait Implementations

impl Freeze for TransitionKind

impl RefUnwindSafe for TransitionKind

impl Send for TransitionKind

impl Sync for TransitionKind

impl Unpin for TransitionKind

impl UnsafeUnpin for TransitionKind

impl UnwindSafe for TransitionKind

Blanket Implementations

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

fn type_id(&self) -> TypeId

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

fn borrow(&self) -> &T

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

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

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

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

impl<T> From<T> for TransitionKind

fn from(t: T) -> T

Returns the argument unchanged.

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

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

impl<T, U> Into<U> for TransitionKind 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 TransitionKind 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 TransitionKind where U: TryFrom<T>,

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