//! The [`Time`] struct and its associated `impl`s.
#[cfg(feature = "formatting")] use alloc::string::String; use core::fmt; use core::ops::{Add, Sub}; use core::time::Duration as StdDuration; #[cfg(feature = "formatting")] use std::io;
use deranged::{RangedU32, RangedU8}; use num_conv::prelude::*; use powerfmt::ext::FormatterExt; use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
/// 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(crate) enum Padding { #[allow(clippy::missing_docs_in_private_items)]
Optimize,
}
/// The type of the `hour` field of `Time`. type Hours = RangedU8<0, { Hour::per(Day) - 1 }>; /// The type of the `minute` field of `Time`. type Minutes = RangedU8<0, { Minute::per(Hour) - 1 }>; /// The type of the `second` field of `Time`. type Seconds = RangedU8<0, { Second::per(Minute) - 1 }>; /// The type of the `nanosecond` field of `Time`. type Nanoseconds = RangedU32<0, { Nanosecond::per(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)] #[repr(C)] pubstruct Time { // The order of this struct's fields matter! // Do not change them.
impl core::hash::Hash for Time { fn hash<H: core::hash::Hasher>(&self, state: &mut H) { self.as_u64().hash(state)
}
}
impl PartialEq for Time { fn eq(&self, other: &Self) -> bool { self.as_u64().eq(&other.as_u64())
}
}
impl PartialOrd for Time { fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Time { fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.as_u64().cmp(&other.as_u64())
}
}
impl Time { /// Provides an u64 based representation **of the correct endianness** /// /// This representation can be used to do comparisons equality testing or hashing. constfn as_u64(self) -> u64 { let nano_bytes = self.nanosecond.get().to_ne_bytes();
/// Create a `Time` that is exactly midnight. /// /// ```rust /// # use time::Time; /// # use time_macros::time; /// assert_eq!(Time::MIDNIGHT, time!(0:00)); /// ``` pubconst MIDNIGHT: Self = Self::MIN;
/// The smallest value that can be represented by `Time`. /// /// `00:00:00.0` pub(crate) const MIN: Self = Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
/// The largest value that can be represented by `Time`. /// /// `23:59:59.999_999_999` pub(crate) const MAX: Self = Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
// region: constructors /// 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)] pubconstunsafefn __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. /// ``` pubconstfn 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. pub(crate) constfn 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. /// ``` pubconstfn 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(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. /// ``` pubconstfn 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(Microsecond) as u32),
))
}
/// 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. /// ``` pubconstfn 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),
))
} // endregion constructors
/// Get the clock hour, minute, second, and nanosecond. #[cfg(feature = "quickcheck")] pub(crate) constfn 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); /// ``` pubconstfn 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); /// ``` pubconstfn 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); /// ``` pubconstfn 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); /// ``` pubconstfn millisecond(self) -> u16 {
(self.nanosecond.get() / Nanosecond::per(Millisecond)) as _
}
/// 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); /// ``` pubconstfn microsecond(self) -> u32 { self.nanosecond.get() / Nanosecond::per(Microsecond) as u32
}
/// 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); /// ``` pubconstfn nanosecond(self) -> u32 { self.nanosecond.get()
} // endregion getters
// region: arithmetic helpers /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether /// the date is different. pub(crate) constfn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) { letmut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds(); letmut seconds = self.second.get() as i8 + (duration.whole_seconds() % Second::per(Minute) as i64) as i8; letmut minutes = self.minute.get() as i8 + (duration.whole_minutes() % Minute::per(Hour) as i64) as i8; letmut hours = self.hour.get() as i8 + (duration.whole_hours() % Hour::per(Day) as i64) as i8; letmut date_adjustment = DateAdjustment::None;
cascade!(nanoseconds in0..Nanosecond::per(Second) as _ => seconds);
cascade!(seconds in0..Second::per(Minute) as _ => minutes);
cascade!(minutes in0..Minute::per(Hour) as _ => hours); if hours >= Hour::per(Day) as _ {
hours -= Hour::per(Day) as i8;
date_adjustment = DateAdjustment::Next;
} elseif hours < 0 {
hours += Hour::per(Day) as i8;
date_adjustment = DateAdjustment::Previous;
}
(
date_adjustment, // Safety: The cascades above ensure the values are in range. unsafe { Self::__from_hms_nanos_unchecked(
hours as _,
minutes as _,
seconds as _,
nanoseconds as _,
)
},
)
}
/// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning /// whether the date is different. pub(crate) constfn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) { letmut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds(); letmut seconds = self.second.get() as i8 - (duration.whole_seconds() % Second::per(Minute) as i64) as i8; letmut minutes = self.minute.get() as i8 - (duration.whole_minutes() % Minute::per(Hour) as i64) as i8; letmut hours = self.hour.get() as i8 - (duration.whole_hours() % Hour::per(Day) as i64) as i8; letmut date_adjustment = DateAdjustment::None;
cascade!(nanoseconds in0..Nanosecond::per(Second) as _ => seconds);
cascade!(seconds in0..Second::per(Minute) as _ => minutes);
cascade!(minutes in0..Minute::per(Hour) as _ => hours); if hours >= Hour::per(Day) as _ {
hours -= Hour::per(Day) as i8;
date_adjustment = DateAdjustment::Next;
} elseif hours < 0 {
hours += Hour::per(Day) as i8;
date_adjustment = DateAdjustment::Previous;
}
(
date_adjustment, // Safety: The cascades above ensure the values are in range. unsafe { Self::__from_hms_nanos_unchecked(
hours as _,
minutes as _,
seconds as _,
nanoseconds as _,
)
},
)
}
/// 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. pub(crate) constfn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) { letmut nanosecond = self.nanosecond.get() + duration.subsec_nanos(); letmut second = self.second.get() + (duration.as_secs() % Second::per(Minute) as u64) as u8; letmut minute = self.minute.get()
+ ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as u8; letmut hour = self.hour.get()
+ ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as u8; letmut is_next_day = false;
(
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. pub(crate) constfn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) { letmut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32; letmut second = self.second.get() as i8 - (duration.as_secs() % Second::per(Minute) as u64) as i8; letmut minute = self.minute.get() as i8
- ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as i8; letmut hour = self.hour.get() as i8
- ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as i8; letmut is_previous_day = false;
cascade!(nanosecond in0..Nanosecond::per(Second) as _ => second);
cascade!(second in0..Second::per(Minute) as _ => minute);
cascade!(minute in0..Minute::per(Hour) as _ => hour); if hour < 0 {
hour += Hour::per(Day) as i8;
is_previous_day = true;
}
(
is_previous_day, // Safety: The cascades above ensure the values are in range. unsafe { Self::__from_hms_nanos_unchecked(
hour as _,
minute as _,
second as _,
nanosecond as _,
)
},
)
} // endregion arithmetic helpers
// region: replacement /// 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`."] pubconstfn replace_hour(mutself, hour: u8) -> Result<Self, error::ComponentRange> { self.hour = ensure_ranged!(Hours: hour);
Ok(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`."] pubconstfn replace_minute(mutself, minute: u8) -> Result<Self, error::ComponentRange> { self.minute = ensure_ranged!(Minutes: minute);
Ok(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`."] pubconstfn replace_second(mutself, second: u8) -> Result<Self, error::ComponentRange> { self.second = ensure_ranged!(Seconds: second);
Ok(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`."] pubconstfn replace_millisecond( mutself,
millisecond: u16,
) -> Result<Self, error::ComponentRange> { self.nanosecond =
ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond));
Ok(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`."] pubconstfn replace_microsecond( mutself,
microsecond: u32,
) -> Result<Self, error::ComponentRange> { self.nanosecond =
ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32);
Ok(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`."] pubconstfn replace_nanosecond( mutself,
nanosecond: u32,
) -> Result<Self, error::ComponentRange> { self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
Ok(self)
} // endregion replacement
}
// region: formatting & parsing #[cfg(feature = "formatting")] impl Time { /// Format the `Time` using the provided [format description](crate::format_description). pubfn format_into( self,
output: &mutimpl io::Write,
format: &(impl Formattable + ?Sized),
) -> Result<usize, error::Format> {
format.format_into(output, None, Some(self), None)
}
/// 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>(()) /// ``` pubfn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
format.format(None, Some(self), None)
}
}
#[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>(()) /// ``` pubfn parse(
input: &str,
description: &(impl Parsable + ?Sized),
) -> Result<Self, error::Parse> {
description.parse_time(input.as_bytes())
}
}
mod private { #[non_exhaustive] #[derive(Debug, Clone, Copy)] pubstruct 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;
// Safety: `nanoseconds` is in range due to the overflow handling. unsafe { Duration::new_unchecked(seconds, nanoseconds) }
}
} // endregion trait impls
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-06-18)
¤
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.