summaryrefslogtreecommitdiffstats
path: root/third_party/rust/time/src/time.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/time/src/time.rs')
-rw-r--r--third_party/rust/time/src/time.rs761
1 files changed, 761 insertions, 0 deletions
diff --git a/third_party/rust/time/src/time.rs b/third_party/rust/time/src/time.rs
new file mode 100644
index 0000000000..32fa97790f
--- /dev/null
+++ b/third_party/rust/time/src/time.rs
@@ -0,0 +1,761 @@
+//! The [`Time`] struct and its associated `impl`s.
+
+use core::fmt;
+use core::ops::{Add, Sub};
+use core::time::Duration as StdDuration;
+#[cfg(feature = "formatting")]
+use std::io;
+
+#[cfg(feature = "formatting")]
+use crate::formatting::Formattable;
+#[cfg(feature = "parsing")]
+use crate::parsing::Parsable;
+use crate::util::DateAdjustment;
+use crate::{error, Duration};
+
+/// 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 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, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct Time {
+ #[allow(clippy::missing_docs_in_private_items)]
+ hour: u8,
+ #[allow(clippy::missing_docs_in_private_items)]
+ minute: u8,
+ #[allow(clippy::missing_docs_in_private_items)]
+ second: u8,
+ #[allow(clippy::missing_docs_in_private_items)]
+ nanosecond: u32,
+ #[allow(clippy::missing_docs_in_private_items)]
+ padding: Padding,
+}
+
+impl Time {
+ /// Create a `Time` that is exactly midnight.
+ ///
+ /// ```rust
+ /// # use time::Time;
+ /// # use time_macros::time;
+ /// assert_eq!(Time::MIDNIGHT, time!(0:00));
+ /// ```
+ pub const MIDNIGHT: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0);
+
+ /// The smallest value that can be represented by `Time`.
+ ///
+ /// `00:00:00.0`
+ pub(crate) const MIN: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0);
+
+ /// The largest value that can be represented by `Time`.
+ ///
+ /// `23:59:59.999_999_999`
+ pub(crate) const MAX: Self = Self::__from_hms_nanos_unchecked(23, 59, 59, 999_999_999);
+
+ // region: constructors
+ /// Create a `Time` from its components.
+ #[doc(hidden)]
+ pub const fn __from_hms_nanos_unchecked(
+ hour: u8,
+ minute: u8,
+ second: u8,
+ nanosecond: u32,
+ ) -> Self {
+ debug_assert!(hour < 24);
+ debug_assert!(minute < 60);
+ debug_assert!(second < 60);
+ debug_assert!(nanosecond < 1_000_000_000);
+
+ Self {
+ hour,
+ minute,
+ second,
+ nanosecond,
+ padding: Padding::Optimize,
+ }
+ }
+
+ /// 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.
+ /// ```
+ pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(hour in 0 => 23);
+ ensure_value_in_range!(minute in 0 => 59);
+ ensure_value_in_range!(second in 0 => 59);
+ Ok(Self::__from_hms_nanos_unchecked(hour, minute, second, 0))
+ }
+
+ /// 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.
+ /// ```
+ pub const fn from_hms_milli(
+ hour: u8,
+ minute: u8,
+ second: u8,
+ millisecond: u16,
+ ) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(hour in 0 => 23);
+ ensure_value_in_range!(minute in 0 => 59);
+ ensure_value_in_range!(second in 0 => 59);
+ ensure_value_in_range!(millisecond in 0 => 999);
+ Ok(Self::__from_hms_nanos_unchecked(
+ hour,
+ minute,
+ second,
+ millisecond as u32 * 1_000_000,
+ ))
+ }
+
+ /// 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.
+ /// ```
+ pub const fn from_hms_micro(
+ hour: u8,
+ minute: u8,
+ second: u8,
+ microsecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(hour in 0 => 23);
+ ensure_value_in_range!(minute in 0 => 59);
+ ensure_value_in_range!(second in 0 => 59);
+ ensure_value_in_range!(microsecond in 0 => 999_999);
+ Ok(Self::__from_hms_nanos_unchecked(
+ hour,
+ minute,
+ second,
+ microsecond * 1_000,
+ ))
+ }
+
+ /// 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.
+ /// ```
+ pub const fn from_hms_nano(
+ hour: u8,
+ minute: u8,
+ second: u8,
+ nanosecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(hour in 0 => 23);
+ ensure_value_in_range!(minute in 0 => 59);
+ ensure_value_in_range!(second in 0 => 59);
+ ensure_value_in_range!(nanosecond in 0 => 999_999_999);
+ Ok(Self::__from_hms_nanos_unchecked(
+ hour, minute, second, nanosecond,
+ ))
+ }
+ // endregion constructors
+
+ // region: getters
+ /// 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));
+ /// ```
+ pub const fn as_hms(self) -> (u8, u8, u8) {
+ (self.hour, self.minute, self.second)
+ }
+
+ /// 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));
+ /// ```
+ pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
+ (
+ self.hour,
+ self.minute,
+ self.second,
+ (self.nanosecond / 1_000_000) 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)
+ /// );
+ /// ```
+ pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
+ (self.hour, self.minute, self.second, self.nanosecond / 1_000)
+ }
+
+ /// 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)
+ /// );
+ /// ```
+ pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
+ (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);
+ /// ```
+ pub const fn hour(self) -> u8 {
+ self.hour
+ }
+
+ /// 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);
+ /// ```
+ pub const fn minute(self) -> u8 {
+ self.minute
+ }
+
+ /// 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);
+ /// ```
+ pub const fn second(self) -> u8 {
+ self.second
+ }
+
+ /// 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);
+ /// ```
+ pub const fn millisecond(self) -> u16 {
+ (self.nanosecond / 1_000_000) 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);
+ /// ```
+ pub const fn microsecond(self) -> u32 {
+ self.nanosecond / 1_000
+ }
+
+ /// 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);
+ /// ```
+ pub const fn nanosecond(self) -> u32 {
+ self.nanosecond
+ }
+ // 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) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
+ let mut nanoseconds = self.nanosecond as i32 + duration.subsec_nanoseconds();
+ let mut seconds = self.second as i8 + (duration.whole_seconds() % 60) as i8;
+ let mut minutes = self.minute as i8 + (duration.whole_minutes() % 60) as i8;
+ let mut hours = self.hour as i8 + (duration.whole_hours() % 24) as i8;
+ let mut date_adjustment = DateAdjustment::None;
+
+ cascade!(nanoseconds in 0..1_000_000_000 => seconds);
+ cascade!(seconds in 0..60 => minutes);
+ cascade!(minutes in 0..60 => hours);
+ if hours >= 24 {
+ hours -= 24;
+ date_adjustment = DateAdjustment::Next;
+ } else if hours < 0 {
+ hours += 24;
+ date_adjustment = DateAdjustment::Previous;
+ }
+
+ (
+ date_adjustment,
+ 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) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
+ let mut nanoseconds = self.nanosecond as i32 - duration.subsec_nanoseconds();
+ let mut seconds = self.second as i8 - (duration.whole_seconds() % 60) as i8;
+ let mut minutes = self.minute as i8 - (duration.whole_minutes() % 60) as i8;
+ let mut hours = self.hour as i8 - (duration.whole_hours() % 24) as i8;
+ let mut date_adjustment = DateAdjustment::None;
+
+ cascade!(nanoseconds in 0..1_000_000_000 => seconds);
+ cascade!(seconds in 0..60 => minutes);
+ cascade!(minutes in 0..60 => hours);
+ if hours >= 24 {
+ hours -= 24;
+ date_adjustment = DateAdjustment::Next;
+ } else if hours < 0 {
+ hours += 24;
+ date_adjustment = DateAdjustment::Previous;
+ }
+
+ (
+ date_adjustment,
+ 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) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
+ let mut nanosecond = self.nanosecond + duration.subsec_nanos();
+ let mut second = self.second + (duration.as_secs() % 60) as u8;
+ let mut minute = self.minute + ((duration.as_secs() / 60) % 60) as u8;
+ let mut hour = self.hour + ((duration.as_secs() / 3_600) % 24) as u8;
+ let mut is_next_day = false;
+
+ cascade!(nanosecond in 0..1_000_000_000 => second);
+ cascade!(second in 0..60 => minute);
+ cascade!(minute in 0..60 => hour);
+ if hour >= 24 {
+ hour -= 24;
+ is_next_day = true;
+ }
+
+ (
+ is_next_day,
+ 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) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
+ let mut nanosecond = self.nanosecond as i32 - duration.subsec_nanos() as i32;
+ let mut second = self.second as i8 - (duration.as_secs() % 60) as i8;
+ let mut minute = self.minute as i8 - ((duration.as_secs() / 60) % 60) as i8;
+ let mut hour = self.hour as i8 - ((duration.as_secs() / 3_600) % 24) as i8;
+ let mut is_previous_day = false;
+
+ cascade!(nanosecond in 0..1_000_000_000 => second);
+ cascade!(second in 0..60 => minute);
+ cascade!(minute in 0..60 => hour);
+ if hour < 0 {
+ hour += 24;
+ is_previous_day = true;
+ }
+
+ (
+ is_previous_day,
+ 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`."]
+ pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(hour in 0 => 23);
+ Ok(Self::__from_hms_nanos_unchecked(
+ hour,
+ self.minute,
+ self.second,
+ self.nanosecond,
+ ))
+ }
+
+ /// 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`."]
+ pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(minute in 0 => 59);
+ Ok(Self::__from_hms_nanos_unchecked(
+ self.hour,
+ minute,
+ self.second,
+ self.nanosecond,
+ ))
+ }
+
+ /// 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`."]
+ pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(second in 0 => 59);
+ Ok(Self::__from_hms_nanos_unchecked(
+ self.hour,
+ self.minute,
+ second,
+ self.nanosecond,
+ ))
+ }
+
+ /// 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`."]
+ pub const fn replace_millisecond(
+ self,
+ millisecond: u16,
+ ) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(millisecond in 0 => 999);
+ Ok(Self::__from_hms_nanos_unchecked(
+ self.hour,
+ self.minute,
+ self.second,
+ millisecond as u32 * 1_000_000,
+ ))
+ }
+
+ /// 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`."]
+ pub const fn replace_microsecond(
+ self,
+ microsecond: u32,
+ ) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(microsecond in 0 => 999_999);
+ Ok(Self::__from_hms_nanos_unchecked(
+ self.hour,
+ self.minute,
+ self.second,
+ microsecond * 1000,
+ ))
+ }
+
+ /// 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`."]
+ pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
+ ensure_value_in_range!(nanosecond in 0 => 999_999_999);
+ Ok(Self::__from_hms_nanos_unchecked(
+ self.hour,
+ self.minute,
+ self.second,
+ nanosecond,
+ ))
+ }
+ // endregion replacement
+}
+
+// region: formatting & parsing
+#[cfg(feature = "formatting")]
+impl Time {
+ /// Format the `Time` using the provided [format description](crate::format_description).
+ pub fn format_into(
+ self,
+ output: &mut impl io::Write,
+ format: &(impl Formattable + ?Sized),
+ ) -> Result<usize, crate::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>(())
+ /// ```
+ pub fn format(
+ self,
+ format: &(impl Formattable + ?Sized),
+ ) -> Result<String, crate::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>(())
+ /// ```
+ pub fn parse(
+ input: &str,
+ description: &(impl Parsable + ?Sized),
+ ) -> Result<Self, error::Parse> {
+ description.parse_time(input.as_bytes())
+ }
+}
+
+impl fmt::Display for Time {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let (value, width) = match self.nanosecond() {
+ nanos if nanos % 10 != 0 => (nanos, 9),
+ nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
+ nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
+ nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
+ nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
+ nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
+ nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
+ nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
+ nanos => (nanos / 100_000_000, 1),
+ };
+ write!(
+ f,
+ "{}:{:02}:{:02}.{value:0width$}",
+ self.hour, self.minute, self.second,
+ )
+ }
+}
+
+impl fmt::Debug for Time {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+// endregion formatting & parsing
+
+// region: trait impls
+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));
+ /// ```
+ fn add(self, duration: Duration) -> Self::Output {
+ self.adjusting_add(duration).1
+ }
+}
+
+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));
+ /// ```
+ fn add(self, duration: StdDuration) -> Self::Output {
+ self.adjusting_add_std(duration).1
+ }
+}
+
+impl_add_assign!(Time: Duration, StdDuration);
+
+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));
+ /// ```
+ fn sub(self, duration: Duration) -> Self::Output {
+ self.adjusting_sub(duration).1
+ }
+}
+
+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));
+ /// ```
+ fn sub(self, duration: StdDuration) -> Self::Output {
+ self.adjusting_sub_std(duration).1
+ }
+}
+
+impl_sub_assign!(Time: Duration, StdDuration);
+
+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());
+ /// ```
+ fn sub(self, rhs: Self) -> Self::Output {
+ let hour_diff = (self.hour as i8) - (rhs.hour as i8);
+ let minute_diff = (self.minute as i8) - (rhs.minute as i8);
+ let second_diff = (self.second as i8) - (rhs.second as i8);
+ let nanosecond_diff = (self.nanosecond as i32) - (rhs.nanosecond as i32);
+
+ let seconds = hour_diff as i64 * 3_600 + minute_diff as i64 * 60 + second_diff as i64;
+
+ let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
+ (seconds - 1, nanosecond_diff + 1_000_000_000)
+ } else if seconds < 0 && nanosecond_diff > 0 {
+ (seconds + 1, nanosecond_diff - 1_000_000_000)
+ } else {
+ (seconds, nanosecond_diff)
+ };
+
+ Duration::new_unchecked(seconds, nanoseconds)
+ }
+}
+// endregion trait impls