Struct AmbiguousZoned
pub struct AmbiguousZoned { /* private fields */ }
dep_jiff
and alloc
only.Expand description
A possibly ambiguous Zoned
, created by
TimeZone::to_ambiguous_zoned
.
While this is called an ambiguous zoned datetime, the thing that is
actually ambiguous is the offset. That is, an ambiguous zoned datetime
is actually a triple of a civil::DateTime
, a
TimeZone
and an AmbiguousOffset
.
When the offset is ambiguous, it either represents a gap (civil time is skipped) or a fold (civil time is repeated). In both cases, there are, by construction, two different offsets to choose from: the offset from before the transition and the offset from after the transition.
The purpose of this type is to represent that ambiguity (when it occurs)
and enable callers to make a choice about how to resolve that ambiguity.
In some cases, you might want to reject ambiguity altogether, which is
supported by the AmbiguousZoned::unambiguous
routine.
This type provides four different out-of-the-box disambiguation strategies:
AmbiguousZoned::compatible
implements theDisambiguation::Compatible
strategy. In the case of a gap, the offset after the gap is selected. In the case of a fold, the offset before the fold occurs is selected.AmbiguousZoned::earlier
implements theDisambiguation::Earlier
strategy. This always selects the “earlier” offset.AmbiguousZoned::later
implements theDisambiguation::Later
strategy. This always selects the “later” offset.AmbiguousZoned::unambiguous
implements theDisambiguation::Reject
strategy. It acts as an assertion that the offset is unambiguous. If it is ambiguous, then an appropriate error is returned.
The AmbiguousZoned::disambiguate
method can be used with the
Disambiguation
enum when the disambiguation strategy isn’t known until
runtime.
Note also that these aren’t the only disambiguation strategies. The
AmbiguousOffset
type, accessible via AmbiguousZoned::offset
,
exposes the full details of the ambiguity. So any strategy can be
implemented.
§Example
This example shows how the “compatible” disambiguation strategy is implemented. Recall that the “compatible” strategy chooses the offset corresponding to the civil datetime after a gap, and the offset corresponding to the civil datetime before a gap.
use jiff::{civil::date, tz::{self, AmbiguousOffset}};
let tz = tz::db().get("America/New_York")?;
let dt = date(2024, 3, 10).at(2, 30, 0, 0);
let ambiguous = tz.to_ambiguous_zoned(dt);
let offset = match ambiguous.offset() {
AmbiguousOffset::Unambiguous { offset } => offset,
// This is counter-intuitive, but in order to get the civil datetime
// *after* the gap, we need to select the offset from *before* the
// gap.
AmbiguousOffset::Gap { before, .. } => before,
AmbiguousOffset::Fold { before, .. } => before,
};
let zdt = offset.to_timestamp(dt)?.to_zoned(ambiguous.into_time_zone());
assert_eq!(zdt.to_string(), "2024-03-10T03:30:00-04:00[America/New_York]");
Implementations§
§impl AmbiguousZoned
impl AmbiguousZoned
pub fn time_zone(&self) -> &TimeZone
pub fn time_zone(&self) -> &TimeZone
Returns a reference to the time zone that was used to create this ambiguous zoned datetime.
§Example
use jiff::{civil::date, tz};
let tz = tz::db().get("America/New_York")?;
let dt = date(2024, 7, 10).at(17, 15, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(&tz, zdt.time_zone());
pub fn into_time_zone(self) -> TimeZone
pub fn into_time_zone(self) -> TimeZone
Consumes this ambiguous zoned datetime and returns the underlying
TimeZone
. This is useful if you no longer need the ambiguous zoned
datetime and want its TimeZone
without cloning it. (Cloning a
TimeZone
is cheap but not free.)
§Example
use jiff::{civil::date, tz};
let tz = tz::db().get("America/New_York")?;
let dt = date(2024, 7, 10).at(17, 15, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(tz, zdt.into_time_zone());
pub fn datetime(&self) -> DateTime
pub fn datetime(&self) -> DateTime
Returns the civil datetime that was used to create this ambiguous zoned datetime.
§Example
use jiff::{civil::date, tz};
let tz = tz::db().get("America/New_York")?;
let dt = date(2024, 7, 10).at(17, 15, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(zdt.datetime(), dt);
pub fn offset(&self) -> AmbiguousOffset
pub fn offset(&self) -> AmbiguousOffset
Returns the possibly ambiguous offset that is the ultimate source of ambiguity.
Most civil datetimes are not ambiguous, and thus, the offset will not
be ambiguous either. In this case, the offset returned will be the
AmbiguousOffset::Unambiguous
variant.
But, not all civil datetimes are unambiguous. There are exactly two cases where a civil datetime can be ambiguous: when a civil datetime does not exist (a gap) or when a civil datetime is repeated (a fold). In both such cases, the offset is the thing that is ambiguous as there are two possible choices for the offset in both cases: the offset before the transition (whether it’s a gap or a fold) or the offset after the transition.
This type captures the fact that computing an offset from a civil datetime in a particular time zone is in one of three possible states:
- It is unambiguous.
- It is ambiguous because there is a gap in time.
- It is ambiguous because there is a fold in time.
§Example
use jiff::{civil::date, tz::{self, AmbiguousOffset}};
let tz = tz::db().get("America/New_York")?;
// Not ambiguous.
let dt = date(2024, 7, 15).at(17, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(zdt.offset(), AmbiguousOffset::Unambiguous {
offset: tz::offset(-4),
});
// Ambiguous because of a gap.
let dt = date(2024, 3, 10).at(2, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(zdt.offset(), AmbiguousOffset::Gap {
before: tz::offset(-5),
after: tz::offset(-4),
});
// Ambiguous because of a fold.
let dt = date(2024, 11, 3).at(1, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(zdt.offset(), AmbiguousOffset::Fold {
before: tz::offset(-4),
after: tz::offset(-5),
});
pub fn is_ambiguous(&self) -> bool
pub fn is_ambiguous(&self) -> bool
Returns true if and only if this possibly ambiguous zoned datetime is actually ambiguous.
This occurs precisely in cases when the offset is not
AmbiguousOffset::Unambiguous
.
§Example
use jiff::{civil::date, tz::{self, AmbiguousOffset}};
let tz = tz::db().get("America/New_York")?;
// Not ambiguous.
let dt = date(2024, 7, 15).at(17, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert!(!zdt.is_ambiguous());
// Ambiguous because of a gap.
let dt = date(2024, 3, 10).at(2, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert!(zdt.is_ambiguous());
// Ambiguous because of a fold.
let dt = date(2024, 11, 3).at(1, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert!(zdt.is_ambiguous());
pub fn compatible(self) -> Result<Zoned, Error> ⓘ
pub fn compatible(self) -> Result<Zoned, Error> ⓘ
Disambiguates this zoned datetime according to the
Disambiguation::Compatible
strategy.
If this zoned datetime is unambiguous, then this is a no-op.
The “compatible” strategy selects the offset corresponding to the civil time after a gap, and the offset corresponding to the civil time before a fold. This is what is specified in RFC 5545.
§Errors
This returns an error when the combination of the civil datetime
and offset would lead to a Zoned
with a timestamp outside of the
Timestamp::MIN
and Timestamp::MAX
limits. This only occurs
when the civil datetime is “close” to its own DateTime::MIN
and DateTime::MAX
limits.
§Example
use jiff::{civil::date, tz};
let tz = tz::db().get("America/New_York")?;
// Not ambiguous.
let dt = date(2024, 7, 15).at(17, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.compatible()?.to_string(),
"2024-07-15T17:30:00-04:00[America/New_York]",
);
// Ambiguous because of a gap.
let dt = date(2024, 3, 10).at(2, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.compatible()?.to_string(),
"2024-03-10T03:30:00-04:00[America/New_York]",
);
// Ambiguous because of a fold.
let dt = date(2024, 11, 3).at(1, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.compatible()?.to_string(),
"2024-11-03T01:30:00-04:00[America/New_York]",
);
pub fn earlier(self) -> Result<Zoned, Error> ⓘ
pub fn earlier(self) -> Result<Zoned, Error> ⓘ
Disambiguates this zoned datetime according to the
Disambiguation::Earlier
strategy.
If this zoned datetime is unambiguous, then this is a no-op.
The “earlier” strategy selects the offset corresponding to the civil time before a gap, and the offset corresponding to the civil time before a fold.
§Errors
This returns an error when the combination of the civil datetime
and offset would lead to a Zoned
with a timestamp outside of the
Timestamp::MIN
and Timestamp::MAX
limits. This only occurs
when the civil datetime is “close” to its own DateTime::MIN
and DateTime::MAX
limits.
§Example
use jiff::{civil::date, tz};
let tz = tz::db().get("America/New_York")?;
// Not ambiguous.
let dt = date(2024, 7, 15).at(17, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.earlier()?.to_string(),
"2024-07-15T17:30:00-04:00[America/New_York]",
);
// Ambiguous because of a gap.
let dt = date(2024, 3, 10).at(2, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.earlier()?.to_string(),
"2024-03-10T01:30:00-05:00[America/New_York]",
);
// Ambiguous because of a fold.
let dt = date(2024, 11, 3).at(1, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.earlier()?.to_string(),
"2024-11-03T01:30:00-04:00[America/New_York]",
);
pub fn later(self) -> Result<Zoned, Error> ⓘ
pub fn later(self) -> Result<Zoned, Error> ⓘ
Disambiguates this zoned datetime according to the
Disambiguation::Later
strategy.
If this zoned datetime is unambiguous, then this is a no-op.
The “later” strategy selects the offset corresponding to the civil time after a gap, and the offset corresponding to the civil time after a fold.
§Errors
This returns an error when the combination of the civil datetime
and offset would lead to a Zoned
with a timestamp outside of the
Timestamp::MIN
and Timestamp::MAX
limits. This only occurs
when the civil datetime is “close” to its own DateTime::MIN
and DateTime::MAX
limits.
§Example
use jiff::{civil::date, tz};
let tz = tz::db().get("America/New_York")?;
// Not ambiguous.
let dt = date(2024, 7, 15).at(17, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.later()?.to_string(),
"2024-07-15T17:30:00-04:00[America/New_York]",
);
// Ambiguous because of a gap.
let dt = date(2024, 3, 10).at(2, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.later()?.to_string(),
"2024-03-10T03:30:00-04:00[America/New_York]",
);
// Ambiguous because of a fold.
let dt = date(2024, 11, 3).at(1, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.later()?.to_string(),
"2024-11-03T01:30:00-05:00[America/New_York]",
);
pub fn unambiguous(self) -> Result<Zoned, Error> ⓘ
pub fn unambiguous(self) -> Result<Zoned, Error> ⓘ
Disambiguates this zoned datetime according to the
Disambiguation::Reject
strategy.
If this zoned datetime is unambiguous, then this is a no-op.
The “reject” strategy always returns an error when the zoned datetime is ambiguous.
§Errors
This returns an error when the combination of the civil datetime
and offset would lead to a Zoned
with a timestamp outside of the
Timestamp::MIN
and Timestamp::MAX
limits. This only occurs
when the civil datetime is “close” to its own DateTime::MIN
and DateTime::MAX
limits.
This also returns an error when the timestamp is ambiguous.
§Example
use jiff::{civil::date, tz};
let tz = tz::db().get("America/New_York")?;
// Not ambiguous.
let dt = date(2024, 7, 15).at(17, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert_eq!(
zdt.later()?.to_string(),
"2024-07-15T17:30:00-04:00[America/New_York]",
);
// Ambiguous because of a gap.
let dt = date(2024, 3, 10).at(2, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert!(zdt.unambiguous().is_err());
// Ambiguous because of a fold.
let dt = date(2024, 11, 3).at(1, 30, 0, 0);
let zdt = tz.to_ambiguous_zoned(dt);
assert!(zdt.unambiguous().is_err());
pub fn disambiguate(self, option: Disambiguation) -> Result<Zoned, Error> ⓘ
pub fn disambiguate(self, option: Disambiguation) -> Result<Zoned, Error> ⓘ
Disambiguates this (possibly ambiguous) timestamp into a concrete time zone aware timestamp.
This is the same as calling one of the disambiguation methods, but the method chosen is indicated by the option given. This is useful when the disambiguation option needs to be chosen at runtime.
§Errors
This returns an error if this would have returned a zoned datetime outside of its minimum and maximum values.
This can also return an error when using the Disambiguation::Reject
strategy. Namely, when using the Reject
strategy, any ambiguous
timestamp always results in an error.
§Example
This example shows the various disambiguation modes when given a datetime that falls in a “fold” (i.e., a backwards DST transition).
use jiff::{civil::date, tz::{self, Disambiguation}};
let newyork = tz::db().get("America/New_York")?;
let dt = date(2024, 11, 3).at(1, 30, 0, 0);
let ambiguous = newyork.to_ambiguous_zoned(dt);
// In compatible mode, backward transitions select the earlier
// time. In the EDT->EST transition, that's the -04 (EDT) offset.
let zdt = ambiguous.clone().disambiguate(Disambiguation::Compatible)?;
assert_eq!(
zdt.to_string(),
"2024-11-03T01:30:00-04:00[America/New_York]",
);
// The earlier time in the EDT->EST transition is the -04 (EDT) offset.
let zdt = ambiguous.clone().disambiguate(Disambiguation::Earlier)?;
assert_eq!(
zdt.to_string(),
"2024-11-03T01:30:00-04:00[America/New_York]",
);
// The later time in the EDT->EST transition is the -05 (EST) offset.
let zdt = ambiguous.clone().disambiguate(Disambiguation::Later)?;
assert_eq!(
zdt.to_string(),
"2024-11-03T01:30:00-05:00[America/New_York]",
);
// Since our datetime is ambiguous, the 'reject' strategy errors.
assert!(ambiguous.disambiguate(Disambiguation::Reject).is_err());
Trait Implementations§
§impl Clone for AmbiguousZoned
impl Clone for AmbiguousZoned
§fn clone(&self) -> AmbiguousZoned
fn clone(&self) -> AmbiguousZoned
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more§impl Debug for AmbiguousZoned
impl Debug for AmbiguousZoned
§impl PartialEq for AmbiguousZoned
impl PartialEq for AmbiguousZoned
impl Eq for AmbiguousZoned
impl StructuralPartialEq for AmbiguousZoned
Auto Trait Implementations§
impl Freeze for AmbiguousZoned
impl RefUnwindSafe for AmbiguousZoned
impl Send for AmbiguousZoned
impl Sync for AmbiguousZoned
impl Unpin for AmbiguousZoned
impl UnwindSafe for AmbiguousZoned
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.