time/
time.rs

1//! The [`Time`] struct and its associated `impl`s.
2
3#[cfg(feature = "formatting")]
4use alloc::string::String;
5use core::fmt;
6use core::ops::{Add, Sub};
7use core::time::Duration as StdDuration;
8#[cfg(feature = "formatting")]
9use std::io;
10
11use deranged::{RangedU32, RangedU8};
12use num_conv::prelude::*;
13use powerfmt::ext::FormatterExt;
14use powerfmt::smart_display::{self, FormatterOptions, Metadata, SmartDisplay};
15
16use crate::convert::*;
17#[cfg(feature = "formatting")]
18use crate::formatting::Formattable;
19use crate::internal_macros::{cascade, ensure_ranged, impl_add_assign, impl_sub_assign};
20#[cfg(feature = "parsing")]
21use crate::parsing::Parsable;
22use crate::util::DateAdjustment;
23use crate::{error, hint, Duration};
24
25/// By explicitly inserting this enum where padding is expected, the compiler is able to better
26/// perform niche value optimization.
27#[repr(u8)]
28#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub(crate) enum Padding {
30    #[allow(clippy::missing_docs_in_private_items)]
31    Optimize,
32}
33
34/// The type of the `hour` field of `Time`.
35type Hours = RangedU8<0, { Hour::per_t::<u8>(Day) - 1 }>;
36/// The type of the `minute` field of `Time`.
37type Minutes = RangedU8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
38/// The type of the `second` field of `Time`.
39type Seconds = RangedU8<0, { Second::per_t::<u8>(Minute) - 1 }>;
40/// The type of the `nanosecond` field of `Time`.
41type Nanoseconds = RangedU32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>;
42
43/// The clock time within a given date. Nanosecond precision.
44///
45/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
46/// (either positive or negative).
47///
48/// When comparing two `Time`s, they are assumed to be in the same calendar date.
49#[derive(Clone, Copy, Eq)]
50#[repr(C)]
51pub struct Time {
52    // The order of this struct's fields matter!
53    // Do not change them.
54
55    // Little endian version
56    #[cfg(target_endian = "little")]
57    nanosecond: Nanoseconds,
58    #[cfg(target_endian = "little")]
59    second: Seconds,
60    #[cfg(target_endian = "little")]
61    minute: Minutes,
62    #[cfg(target_endian = "little")]
63    hour: Hours,
64    #[cfg(target_endian = "little")]
65    padding: Padding,
66
67    // Big endian version
68    #[cfg(target_endian = "big")]
69    padding: Padding,
70    #[cfg(target_endian = "big")]
71    hour: Hours,
72    #[cfg(target_endian = "big")]
73    minute: Minutes,
74    #[cfg(target_endian = "big")]
75    second: Seconds,
76    #[cfg(target_endian = "big")]
77    nanosecond: Nanoseconds,
78}
79
80impl core::hash::Hash for Time {
81    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
82        self.as_u64().hash(state)
83    }
84}
85
86impl PartialEq for Time {
87    fn eq(&self, other: &Self) -> bool {
88        self.as_u64().eq(&other.as_u64())
89    }
90}
91
92impl PartialOrd for Time {
93    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
94        Some(self.cmp(other))
95    }
96}
97
98impl Ord for Time {
99    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
100        self.as_u64().cmp(&other.as_u64())
101    }
102}
103
104impl Time {
105    /// Provides an u64 based representation **of the correct endianness**
106    ///
107    /// This representation can be used to do comparisons equality testing or hashing.
108    const fn as_u64(self) -> u64 {
109        let nano_bytes = self.nanosecond.get().to_ne_bytes();
110
111        #[cfg(target_endian = "big")]
112        return u64::from_be_bytes([
113            self.padding as u8,
114            self.hour.get(),
115            self.minute.get(),
116            self.second.get(),
117            nano_bytes[0],
118            nano_bytes[1],
119            nano_bytes[2],
120            nano_bytes[3],
121        ]);
122
123        #[cfg(target_endian = "little")]
124        return u64::from_le_bytes([
125            nano_bytes[0],
126            nano_bytes[1],
127            nano_bytes[2],
128            nano_bytes[3],
129            self.second.get(),
130            self.minute.get(),
131            self.hour.get(),
132            self.padding as u8,
133        ]);
134    }
135
136    /// A `Time` that is exactly midnight. This is the smallest possible value for a `Time`.
137    ///
138    /// ```rust
139    /// # use time::Time;
140    /// # use time_macros::time;
141    /// assert_eq!(Time::MIDNIGHT, time!(0:00));
142    /// ```
143    #[doc(alias = "MIN")]
144    pub const MIDNIGHT: Self =
145        Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
146
147    /// A `Time` that is one nanosecond before midnight. This is the largest possible value for a
148    /// `Time`.
149    ///
150    /// ```rust
151    /// # use time::Time;
152    /// # use time_macros::time;
153    /// assert_eq!(Time::MAX, time!(23:59:59.999_999_999));
154    /// ```
155    pub const MAX: Self =
156        Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
157
158    /// Create a `Time` from its components.
159    ///
160    /// # Safety
161    ///
162    /// - `hours` must be in the range `0..=23`.
163    /// - `minutes` must be in the range `0..=59`.
164    /// - `seconds` must be in the range `0..=59`.
165    /// - `nanoseconds` must be in the range `0..=999_999_999`.
166    #[doc(hidden)]
167    pub const unsafe fn __from_hms_nanos_unchecked(
168        hour: u8,
169        minute: u8,
170        second: u8,
171        nanosecond: u32,
172    ) -> Self {
173        // Safety: The caller must uphold the safety invariants.
174        unsafe {
175            Self::from_hms_nanos_ranged(
176                Hours::new_unchecked(hour),
177                Minutes::new_unchecked(minute),
178                Seconds::new_unchecked(second),
179                Nanoseconds::new_unchecked(nanosecond),
180            )
181        }
182    }
183
184    /// Attempt to create a `Time` from the hour, minute, and second.
185    ///
186    /// ```rust
187    /// # use time::Time;
188    /// assert!(Time::from_hms(1, 2, 3).is_ok());
189    /// ```
190    ///
191    /// ```rust
192    /// # use time::Time;
193    /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
194    /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
195    /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
196    /// ```
197    pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
198        Ok(Self::from_hms_nanos_ranged(
199            ensure_ranged!(Hours: hour),
200            ensure_ranged!(Minutes: minute),
201            ensure_ranged!(Seconds: second),
202            Nanoseconds::MIN,
203        ))
204    }
205
206    /// Create a `Time` from the hour, minute, second, and nanosecond.
207    pub(crate) const fn from_hms_nanos_ranged(
208        hour: Hours,
209        minute: Minutes,
210        second: Seconds,
211        nanosecond: Nanoseconds,
212    ) -> Self {
213        Self {
214            hour,
215            minute,
216            second,
217            nanosecond,
218            padding: Padding::Optimize,
219        }
220    }
221
222    /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
223    ///
224    /// ```rust
225    /// # use time::Time;
226    /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
227    /// ```
228    ///
229    /// ```rust
230    /// # use time::Time;
231    /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
232    /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
233    /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
234    /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
235    /// ```
236    pub const fn from_hms_milli(
237        hour: u8,
238        minute: u8,
239        second: u8,
240        millisecond: u16,
241    ) -> Result<Self, error::ComponentRange> {
242        Ok(Self::from_hms_nanos_ranged(
243            ensure_ranged!(Hours: hour),
244            ensure_ranged!(Minutes: minute),
245            ensure_ranged!(Seconds: second),
246            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)),
247        ))
248    }
249
250    /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
251    ///
252    /// ```rust
253    /// # use time::Time;
254    /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
255    /// ```
256    ///
257    /// ```rust
258    /// # use time::Time;
259    /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
260    /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
261    /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
262    /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
263    /// ```
264    pub const fn from_hms_micro(
265        hour: u8,
266        minute: u8,
267        second: u8,
268        microsecond: u32,
269    ) -> Result<Self, error::ComponentRange> {
270        Ok(Self::from_hms_nanos_ranged(
271            ensure_ranged!(Hours: hour),
272            ensure_ranged!(Minutes: minute),
273            ensure_ranged!(Seconds: second),
274            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)),
275        ))
276    }
277
278    /// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
279    ///
280    /// ```rust
281    /// # use time::Time;
282    /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
283    /// ```
284    ///
285    /// ```rust
286    /// # use time::Time;
287    /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
288    /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
289    /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
290    /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
291    /// ```
292    pub const fn from_hms_nano(
293        hour: u8,
294        minute: u8,
295        second: u8,
296        nanosecond: u32,
297    ) -> Result<Self, error::ComponentRange> {
298        Ok(Self::from_hms_nanos_ranged(
299            ensure_ranged!(Hours: hour),
300            ensure_ranged!(Minutes: minute),
301            ensure_ranged!(Seconds: second),
302            ensure_ranged!(Nanoseconds: nanosecond),
303        ))
304    }
305
306    /// Get the clock hour, minute, and second.
307    ///
308    /// ```rust
309    /// # use time_macros::time;
310    /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
311    /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
312    /// ```
313    pub const fn as_hms(self) -> (u8, u8, u8) {
314        (self.hour.get(), self.minute.get(), self.second.get())
315    }
316
317    /// Get the clock hour, minute, second, and millisecond.
318    ///
319    /// ```rust
320    /// # use time_macros::time;
321    /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
322    /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
323    /// ```
324    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
325        (
326            self.hour.get(),
327            self.minute.get(),
328            self.second.get(),
329            (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16,
330        )
331    }
332
333    /// Get the clock hour, minute, second, and microsecond.
334    ///
335    /// ```rust
336    /// # use time_macros::time;
337    /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
338    /// assert_eq!(
339    ///     time!(23:59:59.999_999).as_hms_micro(),
340    ///     (23, 59, 59, 999_999)
341    /// );
342    /// ```
343    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
344        (
345            self.hour.get(),
346            self.minute.get(),
347            self.second.get(),
348            self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
349        )
350    }
351
352    /// Get the clock hour, minute, second, and nanosecond.
353    ///
354    /// ```rust
355    /// # use time_macros::time;
356    /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
357    /// assert_eq!(
358    ///     time!(23:59:59.999_999_999).as_hms_nano(),
359    ///     (23, 59, 59, 999_999_999)
360    /// );
361    /// ```
362    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
363        (
364            self.hour.get(),
365            self.minute.get(),
366            self.second.get(),
367            self.nanosecond.get(),
368        )
369    }
370
371    /// Get the clock hour, minute, second, and nanosecond.
372    #[cfg(feature = "quickcheck")]
373    pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
374        (self.hour, self.minute, self.second, self.nanosecond)
375    }
376
377    /// Get the clock hour.
378    ///
379    /// The returned value will always be in the range `0..24`.
380    ///
381    /// ```rust
382    /// # use time_macros::time;
383    /// assert_eq!(time!(0:00:00).hour(), 0);
384    /// assert_eq!(time!(23:59:59).hour(), 23);
385    /// ```
386    pub const fn hour(self) -> u8 {
387        self.hour.get()
388    }
389
390    /// Get the minute within the hour.
391    ///
392    /// The returned value will always be in the range `0..60`.
393    ///
394    /// ```rust
395    /// # use time_macros::time;
396    /// assert_eq!(time!(0:00:00).minute(), 0);
397    /// assert_eq!(time!(23:59:59).minute(), 59);
398    /// ```
399    pub const fn minute(self) -> u8 {
400        self.minute.get()
401    }
402
403    /// Get the second within the minute.
404    ///
405    /// The returned value will always be in the range `0..60`.
406    ///
407    /// ```rust
408    /// # use time_macros::time;
409    /// assert_eq!(time!(0:00:00).second(), 0);
410    /// assert_eq!(time!(23:59:59).second(), 59);
411    /// ```
412    pub const fn second(self) -> u8 {
413        self.second.get()
414    }
415
416    /// Get the milliseconds within the second.
417    ///
418    /// The returned value will always be in the range `0..1_000`.
419    ///
420    /// ```rust
421    /// # use time_macros::time;
422    /// assert_eq!(time!(0:00).millisecond(), 0);
423    /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
424    /// ```
425    pub const fn millisecond(self) -> u16 {
426        (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
427    }
428
429    /// Get the microseconds within the second.
430    ///
431    /// The returned value will always be in the range `0..1_000_000`.
432    ///
433    /// ```rust
434    /// # use time_macros::time;
435    /// assert_eq!(time!(0:00).microsecond(), 0);
436    /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
437    /// ```
438    pub const fn microsecond(self) -> u32 {
439        self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
440    }
441
442    /// Get the nanoseconds within the second.
443    ///
444    /// The returned value will always be in the range `0..1_000_000_000`.
445    ///
446    /// ```rust
447    /// # use time_macros::time;
448    /// assert_eq!(time!(0:00).nanosecond(), 0);
449    /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
450    /// ```
451    pub const fn nanosecond(self) -> u32 {
452        self.nanosecond.get()
453    }
454
455    /// Determine the [`Duration`] that, if added to `self`, would result in the parameter.
456    ///
457    /// ```rust
458    /// # use time::Time;
459    /// # use time::ext::NumericalDuration;
460    /// # use time_macros::time;
461    /// assert_eq!(time!(18:00).duration_until(Time::MIDNIGHT), 6.hours());
462    /// assert_eq!(time!(23:00).duration_until(time!(1:00)), 2.hours());
463    /// ```
464    pub const fn duration_until(self, other: Self) -> Duration {
465        let mut nanoseconds = other.nanosecond.get() as i32 - self.nanosecond.get() as i32;
466        let mut seconds = other.second.get() as i8 - self.second.get() as i8;
467        let mut minutes = other.minute.get() as i8 - self.minute.get() as i8;
468        let mut hours = other.hour.get() as i8 - self.hour.get() as i8;
469
470        // Safety: For all four variables, the bounds are obviously true given the previous bounds
471        // and nature of subtraction.
472        unsafe {
473            hint::assert_unchecked(
474                nanoseconds >= Nanoseconds::MIN.get() as i32 - Nanoseconds::MAX.get() as i32,
475            );
476            hint::assert_unchecked(
477                nanoseconds <= Nanoseconds::MAX.get() as i32 - Nanoseconds::MIN.get() as i32,
478            );
479            hint::assert_unchecked(seconds >= Seconds::MIN.get() as i8 - Seconds::MAX.get() as i8);
480            hint::assert_unchecked(seconds <= Seconds::MAX.get() as i8 - Seconds::MIN.get() as i8);
481            hint::assert_unchecked(minutes >= Minutes::MIN.get() as i8 - Minutes::MAX.get() as i8);
482            hint::assert_unchecked(minutes <= Minutes::MAX.get() as i8 - Minutes::MIN.get() as i8);
483            hint::assert_unchecked(hours >= Hours::MIN.get() as i8 - Hours::MAX.get() as i8);
484            hint::assert_unchecked(hours <= Hours::MAX.get() as i8 - Hours::MIN.get() as i8);
485        }
486
487        if self.as_u64() > other.as_u64() {
488            hours += Hour::per_t::<i8>(Day);
489        }
490
491        cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
492        cascade!(seconds in 0..Second::per_t(Minute) => minutes);
493        cascade!(minutes in 0..Minute::per_t(Hour) => hours);
494
495        // Safety: The range of `nanoseconds` is guaranteed by the cascades above.
496        unsafe {
497            Duration::new_unchecked(
498                hours as i64 * Second::per_t::<i64>(Hour)
499                    + minutes as i64 * Second::per_t::<i64>(Minute)
500                    + seconds as i64,
501                nanoseconds,
502            )
503        }
504    }
505
506    /// Determine the [`Duration`] that, if added to the parameter, would result in `self`.
507    ///
508    /// ```rust
509    /// # use time::Time;
510    /// # use time::ext::NumericalDuration;
511    /// # use time_macros::time;
512    /// assert_eq!(Time::MIDNIGHT.duration_since(time!(18:00)), 6.hours());
513    /// assert_eq!(time!(1:00).duration_since(time!(23:00)), 2.hours());
514    /// ```
515    pub const fn duration_since(self, other: Self) -> Duration {
516        other.duration_until(self)
517    }
518
519    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
520    /// the date is different.
521    pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
522        let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds();
523        let mut seconds = self.second.get() as i8
524            + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
525        let mut minutes =
526            self.minute.get() as i8 + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
527        let mut hours =
528            self.hour.get() as i8 + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
529        let mut date_adjustment = DateAdjustment::None;
530
531        cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
532        cascade!(seconds in 0..Second::per_t(Minute) => minutes);
533        cascade!(minutes in 0..Minute::per_t(Hour) => hours);
534        if hours >= Hour::per_t(Day) {
535            hours -= Hour::per_t::<i8>(Day);
536            date_adjustment = DateAdjustment::Next;
537        } else if hours < 0 {
538            hours += Hour::per_t::<i8>(Day);
539            date_adjustment = DateAdjustment::Previous;
540        }
541
542        (
543            date_adjustment,
544            // Safety: The cascades above ensure the values are in range.
545            unsafe {
546                Self::__from_hms_nanos_unchecked(
547                    hours as u8,
548                    minutes as u8,
549                    seconds as u8,
550                    nanoseconds as u32,
551                )
552            },
553        )
554    }
555
556    /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
557    /// whether the date is different.
558    pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
559        let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
560        let mut seconds = self.second.get() as i8
561            - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
562        let mut minutes =
563            self.minute.get() as i8 - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
564        let mut hours =
565            self.hour.get() as i8 - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
566        let mut date_adjustment = DateAdjustment::None;
567
568        cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
569        cascade!(seconds in 0..Second::per_t(Minute) => minutes);
570        cascade!(minutes in 0..Minute::per_t(Hour) => hours);
571        if hours >= Hour::per_t(Day) {
572            hours -= Hour::per_t::<i8>(Day);
573            date_adjustment = DateAdjustment::Next;
574        } else if hours < 0 {
575            hours += Hour::per_t::<i8>(Day);
576            date_adjustment = DateAdjustment::Previous;
577        }
578
579        (
580            date_adjustment,
581            // Safety: The cascades above ensure the values are in range.
582            unsafe {
583                Self::__from_hms_nanos_unchecked(
584                    hours as u8,
585                    minutes as u8,
586                    seconds as u8,
587                    nanoseconds as u32,
588                )
589            },
590        )
591    }
592
593    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
594    /// returning whether the date is the previous date as the first element of the tuple.
595    pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
596        let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
597        let mut second =
598            self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
599        let mut minute = self.minute.get()
600            + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
601                as u8;
602        let mut hour = self.hour.get()
603            + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
604        let mut is_next_day = false;
605
606        cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
607        cascade!(second in 0..Second::per_t(Minute) => minute);
608        cascade!(minute in 0..Minute::per_t(Hour) => hour);
609        if hour >= Hour::per_t::<u8>(Day) {
610            hour -= Hour::per_t::<u8>(Day);
611            is_next_day = true;
612        }
613
614        (
615            is_next_day,
616            // Safety: The cascades above ensure the values are in range.
617            unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
618        )
619    }
620
621    /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
622    /// returning whether the date is the previous date as the first element of the tuple.
623    pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
624        let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
625        let mut second =
626            self.second.get() as i8 - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
627        let mut minute = self.minute.get() as i8
628            - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
629                as i8;
630        let mut hour = self.hour.get() as i8
631            - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
632        let mut is_previous_day = false;
633
634        cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
635        cascade!(second in 0..Second::per_t(Minute) => minute);
636        cascade!(minute in 0..Minute::per_t(Hour) => hour);
637        if hour < 0 {
638            hour += Hour::per_t::<i8>(Day);
639            is_previous_day = true;
640        }
641
642        (
643            is_previous_day,
644            // Safety: The cascades above ensure the values are in range.
645            unsafe {
646                Self::__from_hms_nanos_unchecked(
647                    hour as u8,
648                    minute as u8,
649                    second as u8,
650                    nanosecond as u32,
651                )
652            },
653        )
654    }
655
656    /// Replace the clock hour.
657    ///
658    /// ```rust
659    /// # use time_macros::time;
660    /// assert_eq!(
661    ///     time!(01:02:03.004_005_006).replace_hour(7),
662    ///     Ok(time!(07:02:03.004_005_006))
663    /// );
664    /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
665    /// ```
666    #[must_use = "This method does not mutate the original `Time`."]
667    pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
668        self.hour = ensure_ranged!(Hours: hour);
669        Ok(self)
670    }
671
672    /// Replace the minutes within the hour.
673    ///
674    /// ```rust
675    /// # use time_macros::time;
676    /// assert_eq!(
677    ///     time!(01:02:03.004_005_006).replace_minute(7),
678    ///     Ok(time!(01:07:03.004_005_006))
679    /// );
680    /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
681    /// ```
682    #[must_use = "This method does not mutate the original `Time`."]
683    pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
684        self.minute = ensure_ranged!(Minutes: minute);
685        Ok(self)
686    }
687
688    /// Replace the seconds within the minute.
689    ///
690    /// ```rust
691    /// # use time_macros::time;
692    /// assert_eq!(
693    ///     time!(01:02:03.004_005_006).replace_second(7),
694    ///     Ok(time!(01:02:07.004_005_006))
695    /// );
696    /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
697    /// ```
698    #[must_use = "This method does not mutate the original `Time`."]
699    pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
700        self.second = ensure_ranged!(Seconds: second);
701        Ok(self)
702    }
703
704    /// Replace the milliseconds within the second.
705    ///
706    /// ```rust
707    /// # use time_macros::time;
708    /// assert_eq!(
709    ///     time!(01:02:03.004_005_006).replace_millisecond(7),
710    ///     Ok(time!(01:02:03.007))
711    /// );
712    /// assert!(time!(01:02:03.004_005_006)
713    ///     .replace_millisecond(1_000)
714    ///     .is_err()); // 1_000 isn't a valid millisecond
715    /// ```
716    #[must_use = "This method does not mutate the original `Time`."]
717    pub const fn replace_millisecond(
718        mut self,
719        millisecond: u16,
720    ) -> Result<Self, error::ComponentRange> {
721        self.nanosecond =
722            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
723        Ok(self)
724    }
725
726    /// Replace the microseconds within the second.
727    ///
728    /// ```rust
729    /// # use time_macros::time;
730    /// assert_eq!(
731    ///     time!(01:02:03.004_005_006).replace_microsecond(7_008),
732    ///     Ok(time!(01:02:03.007_008))
733    /// );
734    /// assert!(time!(01:02:03.004_005_006)
735    ///     .replace_microsecond(1_000_000)
736    ///     .is_err()); // 1_000_000 isn't a valid microsecond
737    /// ```
738    #[must_use = "This method does not mutate the original `Time`."]
739    pub const fn replace_microsecond(
740        mut self,
741        microsecond: u32,
742    ) -> Result<Self, error::ComponentRange> {
743        self.nanosecond =
744            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
745        Ok(self)
746    }
747
748    /// Replace the nanoseconds within the second.
749    ///
750    /// ```rust
751    /// # use time_macros::time;
752    /// assert_eq!(
753    ///     time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
754    ///     Ok(time!(01:02:03.007_008_009))
755    /// );
756    /// assert!(time!(01:02:03.004_005_006)
757    ///     .replace_nanosecond(1_000_000_000)
758    ///     .is_err()); // 1_000_000_000 isn't a valid nanosecond
759    /// ```
760    #[must_use = "This method does not mutate the original `Time`."]
761    pub const fn replace_nanosecond(
762        mut self,
763        nanosecond: u32,
764    ) -> Result<Self, error::ComponentRange> {
765        self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
766        Ok(self)
767    }
768}
769
770#[cfg(feature = "formatting")]
771impl Time {
772    /// Format the `Time` using the provided [format description](crate::format_description).
773    pub fn format_into(
774        self,
775        output: &mut (impl io::Write + ?Sized),
776        format: &(impl Formattable + ?Sized),
777    ) -> Result<usize, error::Format> {
778        format.format_into(output, None, Some(self), None)
779    }
780
781    /// Format the `Time` using the provided [format description](crate::format_description).
782    ///
783    /// ```rust
784    /// # use time::format_description;
785    /// # use time_macros::time;
786    /// let format = format_description::parse("[hour]:[minute]:[second]")?;
787    /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
788    /// # Ok::<_, time::Error>(())
789    /// ```
790    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
791        format.format(None, Some(self), None)
792    }
793}
794
795#[cfg(feature = "parsing")]
796impl Time {
797    /// Parse a `Time` from the input using the provided [format
798    /// description](crate::format_description).
799    ///
800    /// ```rust
801    /// # use time::Time;
802    /// # use time_macros::{time, format_description};
803    /// let format = format_description!("[hour]:[minute]:[second]");
804    /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
805    /// # Ok::<_, time::Error>(())
806    /// ```
807    pub fn parse(
808        input: &str,
809        description: &(impl Parsable + ?Sized),
810    ) -> Result<Self, error::Parse> {
811        description.parse_time(input.as_bytes())
812    }
813}
814
815mod private {
816    #[non_exhaustive]
817    #[derive(Debug, Clone, Copy)]
818    pub struct TimeMetadata {
819        /// How many characters wide the formatted subsecond is.
820        pub(super) subsecond_width: u8,
821        /// The value to use when formatting the subsecond. Leading zeroes will be added as
822        /// necessary.
823        pub(super) subsecond_value: u32,
824    }
825}
826use private::TimeMetadata;
827
828impl SmartDisplay for Time {
829    type Metadata = TimeMetadata;
830
831    fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
832        let (subsecond_value, subsecond_width) = match self.nanosecond() {
833            nanos if nanos % 10 != 0 => (nanos, 9),
834            nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
835            nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
836            nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
837            nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
838            nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
839            nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
840            nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
841            nanos => (nanos / 100_000_000, 1),
842        };
843
844        let formatted_width = smart_display::padded_width_of!(
845            self.hour.get(),
846            ":",
847            self.minute.get() => width(2) fill('0'),
848            ":",
849            self.second.get() => width(2) fill('0'),
850            ".",
851        ) + subsecond_width;
852
853        Metadata::new(
854            formatted_width,
855            self,
856            TimeMetadata {
857                subsecond_width: subsecond_width.truncate(),
858                subsecond_value,
859            },
860        )
861    }
862
863    fn fmt_with_metadata(
864        &self,
865        f: &mut fmt::Formatter<'_>,
866        metadata: Metadata<Self>,
867    ) -> fmt::Result {
868        let subsecond_width = metadata.subsecond_width.extend();
869        let subsecond_value = metadata.subsecond_value;
870
871        f.pad_with_width(
872            metadata.unpadded_width(),
873            format_args!(
874                "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
875                self.hour, self.minute, self.second
876            ),
877        )
878    }
879}
880
881impl fmt::Display for Time {
882    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
883        SmartDisplay::fmt(self, f)
884    }
885}
886
887impl fmt::Debug for Time {
888    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
889        fmt::Display::fmt(self, f)
890    }
891}
892
893impl Add<Duration> for Time {
894    type Output = Self;
895
896    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
897    ///
898    /// ```rust
899    /// # use time::ext::NumericalDuration;
900    /// # use time_macros::time;
901    /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
902    /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
903    /// ```
904    fn add(self, duration: Duration) -> Self::Output {
905        self.adjusting_add(duration).1
906    }
907}
908
909impl Add<StdDuration> for Time {
910    type Output = Self;
911
912    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
913    ///
914    /// ```rust
915    /// # use time::ext::NumericalStdDuration;
916    /// # use time_macros::time;
917    /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
918    /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
919    /// ```
920    fn add(self, duration: StdDuration) -> Self::Output {
921        self.adjusting_add_std(duration).1
922    }
923}
924
925impl_add_assign!(Time: Duration, StdDuration);
926
927impl Sub<Duration> for Time {
928    type Output = Self;
929
930    /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
931    ///
932    /// ```rust
933    /// # use time::ext::NumericalDuration;
934    /// # use time_macros::time;
935    /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
936    /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
937    /// ```
938    fn sub(self, duration: Duration) -> Self::Output {
939        self.adjusting_sub(duration).1
940    }
941}
942
943impl Sub<StdDuration> for Time {
944    type Output = Self;
945
946    /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
947    ///
948    /// ```rust
949    /// # use time::ext::NumericalStdDuration;
950    /// # use time_macros::time;
951    /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
952    /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
953    /// ```
954    fn sub(self, duration: StdDuration) -> Self::Output {
955        self.adjusting_sub_std(duration).1
956    }
957}
958
959impl_sub_assign!(Time: Duration, StdDuration);
960
961impl Sub for Time {
962    type Output = Duration;
963
964    /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
965    /// the same calendar day.
966    ///
967    /// ```rust
968    /// # use time::ext::NumericalDuration;
969    /// # use time_macros::time;
970    /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
971    /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
972    /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
973    /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
974    /// ```
975    fn sub(self, rhs: Self) -> Self::Output {
976        let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
977        let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
978        let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
979        let nanosecond_diff =
980            self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
981
982        let seconds = hour_diff.extend::<i64>() * Second::per_t::<i64>(Hour)
983            + minute_diff.extend::<i64>() * Second::per_t::<i64>(Minute)
984            + second_diff.extend::<i64>();
985
986        let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
987            (
988                seconds - 1,
989                nanosecond_diff + Nanosecond::per_t::<i32>(Second),
990            )
991        } else if seconds < 0 && nanosecond_diff > 0 {
992            (
993                seconds + 1,
994                nanosecond_diff - Nanosecond::per_t::<i32>(Second),
995            )
996        } else {
997            (seconds, nanosecond_diff)
998        };
999
1000        // Safety: `nanoseconds` is in range due to the overflow handling.
1001        unsafe { Duration::new_unchecked(seconds, nanoseconds) }
1002    }
1003}