Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/rust/time/src/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 38 kB image not shown  

Quelle  time.rs

  Sprache: Rust
 

//! The [`Time`] struct and its associated `impl`s.

#[cfg(feature = "formatting")]
use alloc::string::String;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::time::Duration as StdDuration;
use core::{fmt, hint};
#[cfg(feature = "formatting")]
use std::io;

use deranged::{RangedU8, RangedU32};
use num_conv::prelude::*;
use powerfmt::ext::FormatterExt;
use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};

use crate::convert::*;
#[cfg(feature = "formatting")]
use crate::formatting::Formattable;
use crate::internal_macros::{cascade, ensure_ranged};
#[cfg(feature = "parsing")]
use crate::parsing::Parsable;
use crate::util::DateAdjustment;
use crate::{Duration, error};

/// By explicitly inserting this enum where padding is expected, the compiler is able to better
/// perform niche value optimization.
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crateenum Padding {
    #[allow(clippy::missing_docs_in_private_items)]
    Optimize,
}

/// The type of the `hour` field of `Time`.
type Hours = RangedU8<0, { Hour::per_t::<u8>(Day) - 1 }>;
/// The type of the `minute` field of `Time`.
type Minutes = RangedU8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
/// The type of the `second` field of `Time`.
type Seconds = RangedU8<0, { Second::per_t::<u8>(Minute) - 1 }>;
/// The type of the `nanosecond` field of `Time`.
type Nanoseconds = RangedU32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>;

/// The clock time within a given date. Nanosecond precision.
///
/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
/// (either positive or negative).
///
/// When comparing two `Time`s, they are assumed to be in the same calendar date.
#[derive(Clone, Copy, Eq)]
#[cfg_attr(not(docsrs), repr(C))]
pub struct Time {
    // The order of this struct's fields matter! Do not reorder them.

    // Little endian version
    #[cfg(target_endian = "little")]
    nanosecond: Nanoseconds,
    #[cfg(target_endian = "little")]
    second: Seconds,
    #[cfg(target_endian = "little")]
    minute: Minutes,
    #[cfg(target_endian = "little")]
    hour: Hours,
    #[cfg(target_endian = "little")]
    padding: Padding,

    // Big endian version
    #[cfg(target_endian = "big")]
    padding: Padding,
    #[cfg(target_endian = "big")]
    hour: Hours,
    #[cfg(target_endian = "big")]
    minute: Minutes,
    #[cfg(target_endian = "big")]
    second: Seconds,
    #[cfg(target_endian = "big")]
    nanosecond: Nanoseconds,
}

impl Hash for Time {
    #[inline]
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        self.as_u64().hash(state)
    }
}

impl PartialEq for Time {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        self.as_u64().eq(&other.as_u64())
    }
}

impl PartialOrd for Time {
    #[inline]
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Time {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        self.as_u64().cmp(&other.as_u64())
    }
}

impl Time {
    /// Provide a representation of `Time` as a `u64`. This value can be used for equality, hashing,
    /// and ordering.
    #[inline]
    pub(crateconst fn as_u64(self) -> u64 {
        // Safety: `self` is presumed valid because it exists, and any value of `u64` is valid. Size
        // and alignment are enforced by the compiler. There is no implicit padding in either `Time`
        // or `u64`.
        unsafe { core::mem::transmute(self) }
    }

    /// A `Time` that is exactly midnight. This is the smallest possible value for a `Time`.
    ///
    /// ```rust
    /// # use time::Time;
    /// # use time_macros::time;
    /// assert_eq!(Time::MIDNIGHT, time!(0:00));
    /// ```
    #[doc(alias = "MIN")]
    pub const MIDNIGHT: Self =
        Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);

    /// A `Time` that is one nanosecond before midnight. This is the largest possible value for a
    /// `Time`.
    ///
    /// ```rust
    /// # use time::Time;
    /// # use time_macros::time;
    /// assert_eq!(Time::MAX, time!(23:59:59.999_999_999));
    /// ```
    pub const MAX: Self =
        Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);

    /// Create a `Time` from its components.
    ///
    /// # Safety
    ///
    /// - `hours` must be in the range `0..=23`.
    /// - `minutes` must be in the range `0..=59`.
    /// - `seconds` must be in the range `0..=59`.
    /// - `nanoseconds` must be in the range `0..=999_999_999`.
    #[doc(hidden)]
    #[inline]
    #[track_caller]
    pub const unsafe fn __from_hms_nanos_unchecked(
        hour: u8,
        minute: u8,
        second: u8,
        nanosecond: u32,
    ) -> Self {
        // Safety: The caller must uphold the safety invariants.
        unsafe {
            Self::from_hms_nanos_ranged(
                Hours::new_unchecked(hour),
                Minutes::new_unchecked(minute),
                Seconds::new_unchecked(second),
                Nanoseconds::new_unchecked(nanosecond),
            )
        }
    }

    /// Attempt to create a `Time` from the hour, minute, and second.
    ///
    /// ```rust
    /// # use time::Time;
    /// assert!(Time::from_hms(1, 2, 3).is_ok());
    /// ```
    ///
    /// ```rust
    /// # use time::Time;
    /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
    /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
    /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
    /// ```
    #[inline]
    pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
        Ok(Self::from_hms_nanos_ranged(
            ensure_ranged!(Hours: hour),
            ensure_ranged!(Minutes: minute),
            ensure_ranged!(Seconds: second),
            Nanoseconds::MIN,
        ))
    }

    /// Create a `Time` from the hour, minute, second, and nanosecond.
    #[inline]
    pub(crateconst fn from_hms_nanos_ranged(
        hour: Hours,
        minute: Minutes,
        second: Seconds,
        nanosecond: Nanoseconds,
    ) -> Self {
        Self {
            hour,
            minute,
            second,
            nanosecond,
            padding: Padding::Optimize,
        }
    }

    /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
    ///
    /// ```rust
    /// # use time::Time;
    /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
    /// ```
    ///
    /// ```rust
    /// # use time::Time;
    /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
    /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
    /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
    /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
    /// ```
    #[inline]
    pub const fn from_hms_milli(
        hour: u8,
        minute: u8,
        second: u8,
        millisecond: u16,
    ) -> Result<Self, error::ComponentRange> {
        Ok(Self::from_hms_nanos_ranged(
            ensure_ranged!(Hours: hour),
            ensure_ranged!(Minutes: minute),
            ensure_ranged!(Seconds: second),
            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)),
        ))
    }

    /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
    ///
    /// ```rust
    /// # use time::Time;
    /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
    /// ```
    ///
    /// ```rust
    /// # use time::Time;
    /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
    /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
    /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
    /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
    /// ```
    #[inline]
    pub const fn from_hms_micro(
        hour: u8,
        minute: u8,
        second: u8,
        microsecond: u32,
    ) -> Result<Self, error::ComponentRange> {
        Ok(Self::from_hms_nanos_ranged(
            ensure_ranged!(Hours: hour),
            ensure_ranged!(Minutes: minute),
            ensure_ranged!(Seconds: second),
            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)),
        ))
    }

    /// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
    ///
    /// ```rust
    /// # use time::Time;
    /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
    /// ```
    ///
    /// ```rust
    /// # use time::Time;
    /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
    /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
    /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
    /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
    /// ```
    #[inline]
    pub const fn from_hms_nano(
        hour: u8,
        minute: u8,
        second: u8,
        nanosecond: u32,
    ) -> Result<Self, error::ComponentRange> {
        Ok(Self::from_hms_nanos_ranged(
            ensure_ranged!(Hours: hour),
            ensure_ranged!(Minutes: minute),
            ensure_ranged!(Seconds: second),
            ensure_ranged!(Nanoseconds: nanosecond),
        ))
    }

    /// Get the clock hour, minute, and second.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
    /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
    /// ```
    #[inline]
    pub const fn as_hms(self) -> (u8, u8, u8) {
        (self.hour.get(), self.minute.get(), self.second.get())
    }

    /// Get the clock hour, minute, second, and millisecond.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
    /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
    /// ```
    #[inline]
    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
        (
            self.hour.get(),
            self.minute.get(),
            self.second.get(),
            (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16,
        )
    }

    /// Get the clock hour, minute, second, and microsecond.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
    /// assert_eq!(
    ///     time!(23:59:59.999_999).as_hms_micro(),
    ///     (23, 59, 59, 999_999)
    /// );
    /// ```
    #[inline]
    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
        (
            self.hour.get(),
            self.minute.get(),
            self.second.get(),
            self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
        )
    }

    /// Get the clock hour, minute, second, and nanosecond.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
    /// assert_eq!(
    ///     time!(23:59:59.999_999_999).as_hms_nano(),
    ///     (23, 59, 59, 999_999_999)
    /// );
    /// ```
    #[inline]
    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
        (
            self.hour.get(),
            self.minute.get(),
            self.second.get(),
            self.nanosecond.get(),
        )
    }

    /// Get the clock hour, minute, second, and nanosecond.
    #[cfg(feature = "quickcheck")]
    #[inline]
    pub(crateconst fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
        (self.hour, self.minute, self.second, self.nanosecond)
    }

    /// Get the clock hour.
    ///
    /// The returned value will always be in the range `0..24`.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00:00).hour(), 0);
    /// assert_eq!(time!(23:59:59).hour(), 23);
    /// ```
    #[inline]
    pub const fn hour(self) -> u8 {
        self.hour.get()
    }

    /// Get the minute within the hour.
    ///
    /// The returned value will always be in the range `0..60`.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00:00).minute(), 0);
    /// assert_eq!(time!(23:59:59).minute(), 59);
    /// ```
    #[inline]
    pub const fn minute(self) -> u8 {
        self.minute.get()
    }

    /// Get the second within the minute.
    ///
    /// The returned value will always be in the range `0..60`.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00:00).second(), 0);
    /// assert_eq!(time!(23:59:59).second(), 59);
    /// ```
    #[inline]
    pub const fn second(self) -> u8 {
        self.second.get()
    }

    /// Get the milliseconds within the second.
    ///
    /// The returned value will always be in the range `0..1_000`.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00).millisecond(), 0);
    /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
    /// ```
    #[inline]
    pub const fn millisecond(self) -> u16 {
        (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
    }

    /// Get the microseconds within the second.
    ///
    /// The returned value will always be in the range `0..1_000_000`.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00).microsecond(), 0);
    /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
    /// ```
    #[inline]
    pub const fn microsecond(self) -> u32 {
        self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
    }

    /// Get the nanoseconds within the second.
    ///
    /// The returned value will always be in the range `0..1_000_000_000`.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00).nanosecond(), 0);
    /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
    /// ```
    #[inline]
    pub const fn nanosecond(self) -> u32 {
        self.nanosecond.get()
    }

    /// Determine the [`Duration`] that, if added to `self`, would result in the parameter.
    ///
    /// ```rust
    /// # use time::Time;
    /// # use time::ext::NumericalDuration;
    /// # use time_macros::time;
    /// assert_eq!(time!(18:00).duration_until(Time::MIDNIGHT), 6.hours());
    /// assert_eq!(time!(23:00).duration_until(time!(1:00)), 2.hours());
    /// ```
    #[inline]
    pub const fn duration_until(self, other: Self) -> Duration {
        let mut nanoseconds =
            other.nanosecond.get().cast_signed() - self.nanosecond.get().cast_signed();
        let seconds = other.second.get().cast_signed() - self.second.get().cast_signed();
        let minutes = other.minute.get().cast_signed() - self.minute.get().cast_signed();
        let hours = other.hour.get().cast_signed() - self.hour.get().cast_signed();

        // Safety: For all four variables, the bounds are obviously true given the previous bounds
        // and nature of subtraction.
        unsafe {
            hint::assert_unchecked(
                nanoseconds
                    >= Nanoseconds::MIN.get().cast_signed() - Nanoseconds::MAX.get().cast_signed(),
            );
            hint::assert_unchecked(
                nanoseconds
                    <= Nanoseconds::MAX.get().cast_signed() - Nanoseconds::MIN.get().cast_signed(),
            );
            hint::assert_unchecked(
                seconds >= Seconds::MIN.get().cast_signed() - Seconds::MAX.get().cast_signed(),
            );
            hint::assert_unchecked(
                seconds <= Seconds::MAX.get().cast_signed() - Seconds::MIN.get().cast_signed(),
            );
            hint::assert_unchecked(
                minutes >= Minutes::MIN.get().cast_signed() - Minutes::MAX.get().cast_signed(),
            );
            hint::assert_unchecked(
                minutes <= Minutes::MAX.get().cast_signed() - Minutes::MIN.get().cast_signed(),
            );
            hint::assert_unchecked(
                hours >= Hours::MIN.get().cast_signed() - Hours::MAX.get().cast_signed(),
            );
            hint::assert_unchecked(
                hours <= Hours::MAX.get().cast_signed() - Hours::MIN.get().cast_signed(),
            );
        }

        let mut total_seconds = hours as i32 * Second::per_t::<i32>(Hour)
            + minutes as i32 * Second::per_t::<i32>(Minute)
            + seconds as i32;

        cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => total_seconds);

        if total_seconds < 0 {
            total_seconds += Second::per_t::<i32>(Day);
        }

        // Safety: The range of `nanoseconds` is guaranteed by the cascades above.
        unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) }
    }

    /// Determine the [`Duration`] that, if added to the parameter, would result in `self`.
    ///
    /// ```rust
    /// # use time::Time;
    /// # use time::ext::NumericalDuration;
    /// # use time_macros::time;
    /// assert_eq!(Time::MIDNIGHT.duration_since(time!(18:00)), 6.hours());
    /// assert_eq!(time!(1:00).duration_since(time!(23:00)), 2.hours());
    /// ```
    #[inline]
    pub const fn duration_since(self, other: Self) -> Duration {
        other.duration_until(self)
    }

    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
    /// the date is different.
    #[inline]
    pub(crateconst fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
        let mut nanoseconds = self.nanosecond.get().cast_signed() + duration.subsec_nanoseconds();
        let mut seconds = self.second.get().cast_signed()
            + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
        let mut minutes = self.minute.get().cast_signed()
            + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
        let mut hours = self.hour.get().cast_signed()
            + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
        let mut date_adjustment = DateAdjustment::None;

        cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
        cascade!(seconds in 0..Second::per_t(Minute) => minutes);
        cascade!(minutes in 0..Minute::per_t(Hour) => hours);
        if hours >= Hour::per_t(Day) {
            hours -= Hour::per_t::<i8>(Day);
            date_adjustment = DateAdjustment::Next;
        } else if hours < 0 {
            hours += Hour::per_t::<i8>(Day);
            date_adjustment = DateAdjustment::Previous;
        }

        (
            date_adjustment,
            // Safety: The cascades above ensure the values are in range.
            unsafe {
                Self::__from_hms_nanos_unchecked(
                    hours.cast_unsigned(),
                    minutes.cast_unsigned(),
                    seconds.cast_unsigned(),
                    nanoseconds.cast_unsigned(),
                )
            },
        )
    }

    /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
    /// whether the date is different.
    #[inline]
    pub(crateconst fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
        let mut nanoseconds = self.nanosecond.get().cast_signed() - duration.subsec_nanoseconds();
        let mut seconds = self.second.get().cast_signed()
            - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
        let mut minutes = self.minute.get().cast_signed()
            - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
        let mut hours = self.hour.get().cast_signed()
            - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
        let mut date_adjustment = DateAdjustment::None;

        cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
        cascade!(seconds in 0..Second::per_t(Minute) => minutes);
        cascade!(minutes in 0..Minute::per_t(Hour) => hours);
        if hours >= Hour::per_t(Day) {
            hours -= Hour::per_t::<i8>(Day);
            date_adjustment = DateAdjustment::Next;
        } else if hours < 0 {
            hours += Hour::per_t::<i8>(Day);
            date_adjustment = DateAdjustment::Previous;
        }

        (
            date_adjustment,
            // Safety: The cascades above ensure the values are in range.
            unsafe {
                Self::__from_hms_nanos_unchecked(
                    hours.cast_unsigned(),
                    minutes.cast_unsigned(),
                    seconds.cast_unsigned(),
                    nanoseconds.cast_unsigned(),
                )
            },
        )
    }

    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
    /// returning whether the date is the previous date as the first element of the tuple.
    #[inline]
    pub(crateconst fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
        let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
        let mut second =
            self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
        let mut minute = self.minute.get()
            + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
                as u8;
        let mut hour = self.hour.get()
            + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
        let mut is_next_day = false;

        cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
        cascade!(second in 0..Second::per_t(Minute) => minute);
        cascade!(minute in 0..Minute::per_t(Hour) => hour);
        if hour >= Hour::per_t::<u8>(Day) {
            hour -= Hour::per_t::<u8>(Day);
            is_next_day = true;
        }

        (
            is_next_day,
            // Safety: The cascades above ensure the values are in range.
            unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
        )
    }

    /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
    /// returning whether the date is the previous date as the first element of the tuple.
    #[inline]
    pub(crateconst fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
        let mut nanosecond =
            self.nanosecond.get().cast_signed() - duration.subsec_nanos().cast_signed();
        let mut second = self.second.get().cast_signed()
            - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
        let mut minute = self.minute.get().cast_signed()
            - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
                as i8;
        let mut hour = self.hour.get().cast_signed()
            - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
        let mut is_previous_day = false;

        cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
        cascade!(second in 0..Second::per_t(Minute) => minute);
        cascade!(minute in 0..Minute::per_t(Hour) => hour);
        if hour < 0 {
            hour += Hour::per_t::<i8>(Day);
            is_previous_day = true;
        }

        (
            is_previous_day,
            // Safety: The cascades above ensure the values are in range.
            unsafe {
                Self::__from_hms_nanos_unchecked(
                    hour.cast_unsigned(),
                    minute.cast_unsigned(),
                    second.cast_unsigned(),
                    nanosecond.cast_unsigned(),
                )
            },
        )
    }

    /// Replace the clock hour.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).replace_hour(7),
    ///     Ok(time!(07:02:03.004_005_006))
    /// );
    /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
        self.hour = ensure_ranged!(Hours: hour);
        Ok(self)
    }

    /// Truncate the time to the hour, setting the minute, second, and subsecond components to zero.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(time!(01:02:03.004_005_006).truncate_to_hour(), time!(01:00));
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn truncate_to_hour(mut self) -> Self {
        self.minute = Minutes::MIN;
        self.second = Seconds::MIN;
        self.nanosecond = Nanoseconds::MIN;
        self
    }

    /// Replace the minutes within the hour.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).replace_minute(7),
    ///     Ok(time!(01:07:03.004_005_006))
    /// );
    /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
        self.minute = ensure_ranged!(Minutes: minute);
        Ok(self)
    }

    /// Truncate the time to the minute, setting the second and subsecond components to zero.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).truncate_to_minute(),
    ///     time!(01:02)
    /// );
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn truncate_to_minute(mut self) -> Self {
        self.second = Seconds::MIN;
        self.nanosecond = Nanoseconds::MIN;
        self
    }

    /// Replace the seconds within the minute.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).replace_second(7),
    ///     Ok(time!(01:02:07.004_005_006))
    /// );
    /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
        self.second = ensure_ranged!(Seconds: second);
        Ok(self)
    }

    /// Truncate the time to the second, setting the subsecond component to zero.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).truncate_to_second(),
    ///     time!(01:02:03)
    /// );
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn truncate_to_second(mut self) -> Self {
        self.nanosecond = Nanoseconds::MIN;
        self
    }

    /// Replace the milliseconds within the second.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).replace_millisecond(7),
    ///     Ok(time!(01:02:03.007))
    /// );
    /// assert!(
    ///     time!(01:02:03.004_005_006)
    ///         .replace_millisecond(1_000)
    ///         .is_err() // 1_000 isn't a valid millisecond
    /// );
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn replace_millisecond(
        mut self,
        millisecond: u16,
    ) -> Result<Self, error::ComponentRange> {
        self.nanosecond =
            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
        Ok(self)
    }

    /// Truncate the time to the millisecond, setting the microsecond and nanosecond components to
    /// zero.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).truncate_to_millisecond(),
    ///     time!(01:02:03.004)
    /// );
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn truncate_to_millisecond(mut self) -> Self {
        // Safety: Truncating to the millisecond will always produce a valid nanosecond.
        self.nanosecond = unsafe {
            Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000_000))
        };
        self
    }

    /// Replace the microseconds within the second.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).replace_microsecond(7_008),
    ///     Ok(time!(01:02:03.007_008))
    /// );
    /// assert!(
    ///     time!(01:02:03.004_005_006)
    ///         .replace_microsecond(1_000_000)
    ///         .is_err() // 1_000_000 isn't a valid microsecond
    /// );
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn replace_microsecond(
        mut self,
        microsecond: u32,
    ) -> Result<Self, error::ComponentRange> {
        self.nanosecond =
            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
        Ok(self)
    }

    /// Truncate the time to the microsecond, setting the nanosecond component to zero.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).truncate_to_microsecond(),
    ///     time!(01:02:03.004_005)
    /// );
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn truncate_to_microsecond(mut self) -> Self {
        // Safety: Truncating to the microsecond will always produce a valid nanosecond.
        self.nanosecond = unsafe {
            Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000))
        };
        self
    }

    /// Replace the nanoseconds within the second.
    ///
    /// ```rust
    /// # use time_macros::time;
    /// assert_eq!(
    ///     time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
    ///     Ok(time!(01:02:03.007_008_009))
    /// );
    /// assert!(
    ///     time!(01:02:03.004_005_006)
    ///         .replace_nanosecond(1_000_000_000)
    ///         .is_err() // 1_000_000_000 isn't a valid nanosecond
    /// );
    /// ```
    #[must_use = "This method does not mutate the original `Time`."]
    #[inline]
    pub const fn replace_nanosecond(
        mut self,
        nanosecond: u32,
    ) -> Result<Self, error::ComponentRange> {
        self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
        Ok(self)
    }
}

#[cfg(feature = "formatting")]
impl Time {
    /// Format the `Time` using the provided [format description](crate::format_description).
    #[inline]
    pub fn format_into(
        self,
        output: &mut (impl io::Write + ?Sized),
        format: &(impl Formattable + ?Sized),
    ) -> Result<usize, error::Format> {
        format.format_into(output, &self, &mut Default::default())
    }

    /// Format the `Time` using the provided [format description](crate::format_description).
    ///
    /// ```rust
    /// # use time::format_description;
    /// # use time_macros::time;
    /// let format = format_description::parse("[hour]:[minute]:[second]")?;
    /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
    /// # Ok::<_, time::Error>(())
    /// ```
    #[inline]
    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
        format.format(&self, &mut Default::default())
    }
}

#[cfg(feature = "parsing")]
impl Time {
    /// Parse a `Time` from the input using the provided [format
    /// description](crate::format_description).
    ///
    /// ```rust
    /// # use time::Time;
    /// # use time_macros::{time, format_description};
    /// let format = format_description!("[hour]:[minute]:[second]");
    /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
    /// # Ok::<_, time::Error>(())
    /// ```
    #[inline]
    pub fn parse(
        input: &str,
        description: &(impl Parsable + ?Sized),
    ) -> Result<Self, error::Parse> {
        description.parse_time(input.as_bytes())
    }
}

mod private {
    /// Metadata for `Time`.
    #[non_exhaustive]
    #[derive(Debug, Clone, Copy)]
    pub struct TimeMetadata {
        /// How many characters wide the formatted subsecond is.
        pub(super) subsecond_width: u8,
        /// The value to use when formatting the subsecond. Leading zeroes will be added as
        /// necessary.
        pub(super) subsecond_value: u32,
    }
}
use private::TimeMetadata;

impl SmartDisplay for Time {
    type Metadata = TimeMetadata;

    #[inline]
    fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
        let (subsecond_value, subsecond_width) = match self.nanosecond() {
            nanos if nanos % 10 != 0 => (nanos, 9),
            nanos if (nanos / 10) % 10 != 0 => (nanos / 108),
            nanos if (nanos / 100) % 10 != 0 => (nanos / 1007),
            nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_0006),
            nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_0005),
            nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_0004),
            nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_0003),
            nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_0002),
            nanos => (nanos / 100_000_0001),
        };

        let formatted_width = smart_display::padded_width_of!(
            self.hour.get(),
            ":",
            self.minute.get() => width(2) fill('0'),
            ":",
            self.second.get() => width(2) fill('0'),
            ".",
        ) + subsecond_width;

        Metadata::new(
            formatted_width,
            self,
            TimeMetadata {
                subsecond_width: subsecond_width.truncate(),
                subsecond_value,
            },
        )
    }

    #[inline]
    fn fmt_with_metadata(
        &self,
        f: &mut fmt::Formatter<'_>,
        metadata: Metadata<Self>,
    ) -> fmt::Result {
        let subsecond_width = metadata.subsecond_width.extend();
        let subsecond_value = metadata.subsecond_value;

        f.pad_with_width(
            metadata.unpadded_width(),
            format_args!(
                "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
                self.hour, self.minute, self.second
            ),
        )
    }
}

impl fmt::Display for Time {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        SmartDisplay::fmt(self, f)
    }
}

impl fmt::Debug for Time {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl Add<Duration> for Time {
    type Output = Self;

    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
    ///
    /// ```rust
    /// # use time::ext::NumericalDuration;
    /// # use time_macros::time;
    /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
    /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
    /// ```
    #[inline]
    fn add(self, duration: Duration) -> Self::Output {
        self.adjusting_add(duration).1
    }
}

impl AddAssign<Duration> for Time {
    #[inline]
    fn add_assign(&mut self, rhs: Duration) {
        *self = *self + rhs;
    }
}

impl Add<StdDuration> for Time {
    type Output = Self;

    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
    ///
    /// ```rust
    /// # use time::ext::NumericalStdDuration;
    /// # use time_macros::time;
    /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
    /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
    /// ```
    #[inline]
    fn add(self, duration: StdDuration) -> Self::Output {
        self.adjusting_add_std(duration).1
    }
}

impl AddAssign<StdDuration> for Time {
    #[inline]
    fn add_assign(&mut self, rhs: StdDuration) {
        *self = *self + rhs;
    }
}

impl Sub<Duration> for Time {
    type Output = Self;

    /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
    ///
    /// ```rust
    /// # use time::ext::NumericalDuration;
    /// # use time_macros::time;
    /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
    /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
    /// ```
    #[inline]
    fn sub(self, duration: Duration) -> Self::Output {
        self.adjusting_sub(duration).1
    }
}

impl SubAssign<Duration> for Time {
    #[inline]
    fn sub_assign(&mut self, rhs: Duration) {
        *self = *self - rhs;
    }
}

impl Sub<StdDuration> for Time {
    type Output = Self;

    /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
    ///
    /// ```rust
    /// # use time::ext::NumericalStdDuration;
    /// # use time_macros::time;
    /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
    /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
    /// ```
    #[inline]
    fn sub(self, duration: StdDuration) -> Self::Output {
        self.adjusting_sub_std(duration).1
    }
}

impl SubAssign<StdDuration> for Time {
    #[inline]
    fn sub_assign(&mut self, rhs: StdDuration) {
        *self = *self - rhs;
    }
}

impl Sub for Time {
    type Output = Duration;

    /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
    /// the same calendar day.
    ///
    /// ```rust
    /// # use time::ext::NumericalDuration;
    /// # use time_macros::time;
    /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
    /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
    /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
    /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
    /// ```
    #[inline]
    fn sub(self, rhs: Self) -> Self::Output {
        let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
        let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
        let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
        let nanosecond_diff =
            self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();

        let seconds = hour_diff.extend::<i32>() * Second::per_t::<i32>(Hour)
            + minute_diff.extend::<i32>() * Second::per_t::<i32>(Minute)
            + second_diff.extend::<i32>();

        let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
            (
                seconds - 1,
                nanosecond_diff + Nanosecond::per_t::<i32>(Second),
            )
        } else if seconds < 0 && nanosecond_diff > 0 {
            (
                seconds + 1,
                nanosecond_diff - Nanosecond::per_t::<i32>(Second),
            )
        } else {
            (seconds, nanosecond_diff)
        };

        // Safety: `nanoseconds` is in range due to the overflow handling.
        unsafe { Duration::new_unchecked(seconds.extend(), nanoseconds) }
    }
}

Messung V0.5 in Prozent
C=68 H=95 G=82

¤ Dauer der Verarbeitung: 0.13 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.