Skip to content

Commit

Permalink
Extend documentation for MappedLocalTime
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker committed Mar 12, 2024
1 parent 1aeaaed commit 6969d9e
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 13 deletions.
21 changes: 20 additions & 1 deletion src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::format::{write_rfc2822, write_rfc3339, DelayedFormat, SecondsFormat};
use crate::naive::{Days, IsoWeek, NaiveDate, NaiveDateTime, NaiveTime};
#[cfg(feature = "clock")]
use crate::offset::Local;
use crate::offset::{FixedOffset, Offset, TimeZone, Utc};
use crate::offset::{FixedOffset, LocalResult, Offset, TimeZone, Utc};
#[allow(deprecated)]
use crate::Date;
use crate::{expect, try_opt};
Expand Down Expand Up @@ -184,6 +184,25 @@ impl<Tz: TimeZone> DateTime<Tz> {
self.datetime.time() + self.offset.fix()
}

/// Set the time to a new fixed time on the existing date.
///
/// # Example
///
/// ```
/// # use chrono::{Local, NaiveTime};
/// let noon = NaiveTime::from_hms_opt(12, 0, 0).unwrap();
/// let today_noon = Local::now().set_time(noon);
/// let today_midnight = Local::now().set_time(NaiveTime::MIN);
///
/// assert_eq!(today_noon.single().unwrap().time(), noon);
/// assert_eq!(today_midnight.single().unwrap().time(), NaiveTime::MIN);
/// ```
#[must_use]
pub fn set_time(&self, time: NaiveTime) -> LocalResult<Self> {
let timezone: Tz = self.timezone();
timezone.from_local_datetime(&self.date_naive().and_time(time))
}

/// Returns the number of non-leap seconds since January 1, 1970 0:00:00 UTC
/// (aka "UNIX timestamp").
///
Expand Down
67 changes: 55 additions & 12 deletions src/offset/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,47 @@ pub use self::local::Local;
pub(crate) mod utc;
pub use self::utc::Utc;

/// The conversion result from the local time to the timezone-aware datetime types.
/// The result of mapping a local time to a concrete instant in a given time zone.
///
/// The calculation to go from a local time (wall clock time) to an instant in UTC can end up in
/// three cases:
/// * A single, simple result.
/// * An ambiguous result when the clock is turned backwards during a transition due to for example
/// DST.
/// * No result when the clock is turned forwards during a transition due to for example DST.
///
/// When the clock is turned backwards it creates a _fold_ in local time, during which the local
/// time is _ambiguous_. When the clock is turned forwards it creates a _gap_ in local time, during
/// which the local time is _missing_, or does not exist.
///
/// Chrono does not return a default choice or invalid data during time zone transitions, but has
/// the `MappedLocalTime` type to help deal with the result correctly.
///
/// The type of `T` is usually a [`DateTime`] but may also be only an offset.
#[derive(Clone, PartialEq, Debug, Copy, Eq, Hash)]
pub enum MappedLocalTime<T> {
/// Given local time representation is invalid.
/// This can occur when, for example, the positive timezone transition.
None,
/// Given local time representation has a single unique result.
/// The local time maps to a single unique result.
Single(T),
/// Given local time representation has multiple results and thus ambiguous.
/// This can occur when, for example, the negative timezone transition.
Ambiguous(T /* min */, T /* max */),

/// The local time is _ambiguous_ because there is a _fold_ in the local time.
///
/// This variant contains the two possible results, in the order `(earliest, latest)`.
Ambiguous(T, T),

/// The local time does not exist because there is a _gap_ in the local time.
///
/// This variant may also be returned if there was an error while resolving the local time,
/// caused by for example missing time zone data files, an error in an OS API, or overflow.
None,
}

impl<T> MappedLocalTime<T> {
/// Returns `Some` only when the conversion result is unique, or `None` otherwise.
/// Returns `Some` if the time zone mapping has a single result.
///
/// # Errors
///
/// Returns `None` if local time falls in a _fold_ or _gap_ in the local time, or if there was
/// an error.
#[must_use]
pub fn single(self) -> Option<T> {
match self {
Expand All @@ -60,7 +86,11 @@ impl<T> MappedLocalTime<T> {
}
}

/// Returns `Some` for the earliest possible conversion result, or `None` if none.
/// Returns the earliest possible result of a the time zone mapping.
///
/// # Errors
///
/// Returns `None` if local time falls in a _gap_ in the local time, or if there was an error.
#[must_use]
pub fn earliest(self) -> Option<T> {
match self {
Expand All @@ -69,7 +99,11 @@ impl<T> MappedLocalTime<T> {
}
}

/// Returns `Some` for the latest possible conversion result, or `None` if none.
/// Returns the latest possible result of a the time zone mapping.
///
/// # Errors
///
/// Returns `None` if local time falls in a _gap_ in the local time, or if there was an error.
#[must_use]
pub fn latest(self) -> Option<T> {
match self {
Expand Down Expand Up @@ -192,7 +226,16 @@ impl<Tz: TimeZone> MappedLocalTime<Date<Tz>> {
}

impl<T: fmt::Debug> MappedLocalTime<T> {
/// Returns the single unique conversion result, or panics accordingly.
/// Returns a single unique conversion result or panics.
///
/// `unwrap()` is best combined with time zone types where the mapping can never fail like
/// [`Utc`] and [`FixedOffset`]. Note that for [`FixedOffset`] there is a rare case where a
/// resulting [`DateTime`] can be out of range.
///
/// # Panics
///
/// Panics if the local time falls within a _fold_ or a _gap_ in the local time, and on any
/// error that may have been returned by the type implementing [`TimeZone`].
#[must_use]
#[track_caller]
pub fn unwrap(self) -> T {
Expand Down

0 comments on commit 6969d9e

Please sign in to comment.