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, 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(Day) - 1 }>;
36/// The type of the `minute` field of `Time`.
37type Minutes = RangedU8<0, { Minute::per(Hour) - 1 }>;
38/// The type of the `second` field of `Time`.
39type Seconds = RangedU8<0, { Second::per(Minute) - 1 }>;
40/// The type of the `nanosecond` field of `Time`.
41type Nanoseconds = RangedU32<0, { Nanosecond::per(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    // region: constructors
159    /// Create a `Time` from its components.
160    ///
161    /// # Safety
162    ///
163    /// - `hours` must be in the range `0..=23`.
164    /// - `minutes` must be in the range `0..=59`.
165    /// - `seconds` must be in the range `0..=59`.
166    /// - `nanoseconds` must be in the range `0..=999_999_999`.
167    #[doc(hidden)]
168    pub const unsafe fn __from_hms_nanos_unchecked(
169        hour: u8,
170        minute: u8,
171        second: u8,
172        nanosecond: u32,
173    ) -> Self {
174        // Safety: The caller must uphold the safety invariants.
175        unsafe {
176            Self::from_hms_nanos_ranged(
177                Hours::new_unchecked(hour),
178                Minutes::new_unchecked(minute),
179                Seconds::new_unchecked(second),
180                Nanoseconds::new_unchecked(nanosecond),
181            )
182        }
183    }
184
185    /// Attempt to create a `Time` from the hour, minute, and second.
186    ///
187    /// ```rust
188    /// # use time::Time;
189    /// assert!(Time::from_hms(1, 2, 3).is_ok());
190    /// ```
191    ///
192    /// ```rust
193    /// # use time::Time;
194    /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
195    /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
196    /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
197    /// ```
198    pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
199        Ok(Self::from_hms_nanos_ranged(
200            ensure_ranged!(Hours: hour),
201            ensure_ranged!(Minutes: minute),
202            ensure_ranged!(Seconds: second),
203            Nanoseconds::MIN,
204        ))
205    }
206
207    /// Create a `Time` from the hour, minute, second, and nanosecond.
208    pub(crate) const fn from_hms_nanos_ranged(
209        hour: Hours,
210        minute: Minutes,
211        second: Seconds,
212        nanosecond: Nanoseconds,
213    ) -> Self {
214        Self {
215            hour,
216            minute,
217            second,
218            nanosecond,
219            padding: Padding::Optimize,
220        }
221    }
222
223    /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
224    ///
225    /// ```rust
226    /// # use time::Time;
227    /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
228    /// ```
229    ///
230    /// ```rust
231    /// # use time::Time;
232    /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
233    /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
234    /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
235    /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
236    /// ```
237    pub const fn from_hms_milli(
238        hour: u8,
239        minute: u8,
240        second: u8,
241        millisecond: u16,
242    ) -> Result<Self, error::ComponentRange> {
243        Ok(Self::from_hms_nanos_ranged(
244            ensure_ranged!(Hours: hour),
245            ensure_ranged!(Minutes: minute),
246            ensure_ranged!(Seconds: second),
247            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond)),
248        ))
249    }
250
251    /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
252    ///
253    /// ```rust
254    /// # use time::Time;
255    /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
256    /// ```
257    ///
258    /// ```rust
259    /// # use time::Time;
260    /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
261    /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
262    /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
263    /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
264    /// ```
265    pub const fn from_hms_micro(
266        hour: u8,
267        minute: u8,
268        second: u8,
269        microsecond: u32,
270    ) -> Result<Self, error::ComponentRange> {
271        Ok(Self::from_hms_nanos_ranged(
272            ensure_ranged!(Hours: hour),
273            ensure_ranged!(Minutes: minute),
274            ensure_ranged!(Seconds: second),
275            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32),
276        ))
277    }
278
279    /// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
280    ///
281    /// ```rust
282    /// # use time::Time;
283    /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
284    /// ```
285    ///
286    /// ```rust
287    /// # use time::Time;
288    /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
289    /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
290    /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
291    /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
292    /// ```
293    pub const fn from_hms_nano(
294        hour: u8,
295        minute: u8,
296        second: u8,
297        nanosecond: u32,
298    ) -> Result<Self, error::ComponentRange> {
299        Ok(Self::from_hms_nanos_ranged(
300            ensure_ranged!(Hours: hour),
301            ensure_ranged!(Minutes: minute),
302            ensure_ranged!(Seconds: second),
303            ensure_ranged!(Nanoseconds: nanosecond),
304        ))
305    }
306    // endregion constructors
307
308    // region: getters
309    /// Get the clock hour, minute, and second.
310    ///
311    /// ```rust
312    /// # use time_macros::time;
313    /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
314    /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
315    /// ```
316    pub const fn as_hms(self) -> (u8, u8, u8) {
317        (self.hour.get(), self.minute.get(), self.second.get())
318    }
319
320    /// Get the clock hour, minute, second, and millisecond.
321    ///
322    /// ```rust
323    /// # use time_macros::time;
324    /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
325    /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
326    /// ```
327    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
328        (
329            self.hour.get(),
330            self.minute.get(),
331            self.second.get(),
332            (self.nanosecond.get() / Nanosecond::per(Millisecond)) as u16,
333        )
334    }
335
336    /// Get the clock hour, minute, second, and microsecond.
337    ///
338    /// ```rust
339    /// # use time_macros::time;
340    /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
341    /// assert_eq!(
342    ///     time!(23:59:59.999_999).as_hms_micro(),
343    ///     (23, 59, 59, 999_999)
344    /// );
345    /// ```
346    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
347        (
348            self.hour.get(),
349            self.minute.get(),
350            self.second.get(),
351            self.nanosecond.get() / Nanosecond::per(Microsecond) as u32,
352        )
353    }
354
355    /// Get the clock hour, minute, second, and nanosecond.
356    ///
357    /// ```rust
358    /// # use time_macros::time;
359    /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
360    /// assert_eq!(
361    ///     time!(23:59:59.999_999_999).as_hms_nano(),
362    ///     (23, 59, 59, 999_999_999)
363    /// );
364    /// ```
365    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
366        (
367            self.hour.get(),
368            self.minute.get(),
369            self.second.get(),
370            self.nanosecond.get(),
371        )
372    }
373
374    /// Get the clock hour, minute, second, and nanosecond.
375    #[cfg(feature = "quickcheck")]
376    pub(crate) const fn as_hms_nano_ranged(self) -> (Hours, Minutes, Seconds, Nanoseconds) {
377        (self.hour, self.minute, self.second, self.nanosecond)
378    }
379
380    /// Get the clock hour.
381    ///
382    /// The returned value will always be in the range `0..24`.
383    ///
384    /// ```rust
385    /// # use time_macros::time;
386    /// assert_eq!(time!(0:00:00).hour(), 0);
387    /// assert_eq!(time!(23:59:59).hour(), 23);
388    /// ```
389    pub const fn hour(self) -> u8 {
390        self.hour.get()
391    }
392
393    /// Get the minute within the hour.
394    ///
395    /// The returned value will always be in the range `0..60`.
396    ///
397    /// ```rust
398    /// # use time_macros::time;
399    /// assert_eq!(time!(0:00:00).minute(), 0);
400    /// assert_eq!(time!(23:59:59).minute(), 59);
401    /// ```
402    pub const fn minute(self) -> u8 {
403        self.minute.get()
404    }
405
406    /// Get the second within the minute.
407    ///
408    /// The returned value will always be in the range `0..60`.
409    ///
410    /// ```rust
411    /// # use time_macros::time;
412    /// assert_eq!(time!(0:00:00).second(), 0);
413    /// assert_eq!(time!(23:59:59).second(), 59);
414    /// ```
415    pub const fn second(self) -> u8 {
416        self.second.get()
417    }
418
419    /// Get the milliseconds within the second.
420    ///
421    /// The returned value will always be in the range `0..1_000`.
422    ///
423    /// ```rust
424    /// # use time_macros::time;
425    /// assert_eq!(time!(0:00).millisecond(), 0);
426    /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
427    /// ```
428    pub const fn millisecond(self) -> u16 {
429        (self.nanosecond.get() / Nanosecond::per(Millisecond)) as _
430    }
431
432    /// Get the microseconds within the second.
433    ///
434    /// The returned value will always be in the range `0..1_000_000`.
435    ///
436    /// ```rust
437    /// # use time_macros::time;
438    /// assert_eq!(time!(0:00).microsecond(), 0);
439    /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
440    /// ```
441    pub const fn microsecond(self) -> u32 {
442        self.nanosecond.get() / Nanosecond::per(Microsecond) as u32
443    }
444
445    /// Get the nanoseconds within the second.
446    ///
447    /// The returned value will always be in the range `0..1_000_000_000`.
448    ///
449    /// ```rust
450    /// # use time_macros::time;
451    /// assert_eq!(time!(0:00).nanosecond(), 0);
452    /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
453    /// ```
454    pub const fn nanosecond(self) -> u32 {
455        self.nanosecond.get()
456    }
457    // endregion getters
458
459    // region: arithmetic helpers
460    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
461    /// the date is different.
462    pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
463        let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds();
464        let mut seconds =
465            self.second.get() as i8 + (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
466        let mut minutes =
467            self.minute.get() as i8 + (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
468        let mut hours =
469            self.hour.get() as i8 + (duration.whole_hours() % Hour::per(Day) as i64) as i8;
470        let mut date_adjustment = DateAdjustment::None;
471
472        cascade!(nanoseconds in 0..Nanosecond::per(Second) as _ => seconds);
473        cascade!(seconds in 0..Second::per(Minute) as _ => minutes);
474        cascade!(minutes in 0..Minute::per(Hour) as _ => hours);
475        if hours >= Hour::per(Day) as _ {
476            hours -= Hour::per(Day) as i8;
477            date_adjustment = DateAdjustment::Next;
478        } else if hours < 0 {
479            hours += Hour::per(Day) as i8;
480            date_adjustment = DateAdjustment::Previous;
481        }
482
483        (
484            date_adjustment,
485            // Safety: The cascades above ensure the values are in range.
486            unsafe {
487                Self::__from_hms_nanos_unchecked(
488                    hours as _,
489                    minutes as _,
490                    seconds as _,
491                    nanoseconds as _,
492                )
493            },
494        )
495    }
496
497    /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
498    /// whether the date is different.
499    pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
500        let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
501        let mut seconds =
502            self.second.get() as i8 - (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
503        let mut minutes =
504            self.minute.get() as i8 - (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
505        let mut hours =
506            self.hour.get() as i8 - (duration.whole_hours() % Hour::per(Day) as i64) as i8;
507        let mut date_adjustment = DateAdjustment::None;
508
509        cascade!(nanoseconds in 0..Nanosecond::per(Second) as _ => seconds);
510        cascade!(seconds in 0..Second::per(Minute) as _ => minutes);
511        cascade!(minutes in 0..Minute::per(Hour) as _ => hours);
512        if hours >= Hour::per(Day) as _ {
513            hours -= Hour::per(Day) as i8;
514            date_adjustment = DateAdjustment::Next;
515        } else if hours < 0 {
516            hours += Hour::per(Day) as i8;
517            date_adjustment = DateAdjustment::Previous;
518        }
519
520        (
521            date_adjustment,
522            // Safety: The cascades above ensure the values are in range.
523            unsafe {
524                Self::__from_hms_nanos_unchecked(
525                    hours as _,
526                    minutes as _,
527                    seconds as _,
528                    nanoseconds as _,
529                )
530            },
531        )
532    }
533
534    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
535    /// returning whether the date is the previous date as the first element of the tuple.
536    pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
537        let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
538        let mut second =
539            self.second.get() + (duration.as_secs() % Second::per(Minute) as u64) as u8;
540        let mut minute = self.minute.get()
541            + ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as u8;
542        let mut hour = self.hour.get()
543            + ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as u8;
544        let mut is_next_day = false;
545
546        cascade!(nanosecond in 0..Nanosecond::per(Second) => second);
547        cascade!(second in 0..Second::per(Minute) => minute);
548        cascade!(minute in 0..Minute::per(Hour) => hour);
549        if hour >= Hour::per(Day) {
550            hour -= Hour::per(Day);
551            is_next_day = true;
552        }
553
554        (
555            is_next_day,
556            // Safety: The cascades above ensure the values are in range.
557            unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
558        )
559    }
560
561    /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
562    /// returning whether the date is the previous date as the first element of the tuple.
563    pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
564        let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
565        let mut second =
566            self.second.get() as i8 - (duration.as_secs() % Second::per(Minute) as u64) as i8;
567        let mut minute = self.minute.get() as i8
568            - ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as i8;
569        let mut hour = self.hour.get() as i8
570            - ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as i8;
571        let mut is_previous_day = false;
572
573        cascade!(nanosecond in 0..Nanosecond::per(Second) as _ => second);
574        cascade!(second in 0..Second::per(Minute) as _ => minute);
575        cascade!(minute in 0..Minute::per(Hour) as _ => hour);
576        if hour < 0 {
577            hour += Hour::per(Day) as i8;
578            is_previous_day = true;
579        }
580
581        (
582            is_previous_day,
583            // Safety: The cascades above ensure the values are in range.
584            unsafe {
585                Self::__from_hms_nanos_unchecked(
586                    hour as _,
587                    minute as _,
588                    second as _,
589                    nanosecond as _,
590                )
591            },
592        )
593    }
594    // endregion arithmetic helpers
595
596    // region: replacement
597    /// Replace the clock hour.
598    ///
599    /// ```rust
600    /// # use time_macros::time;
601    /// assert_eq!(
602    ///     time!(01:02:03.004_005_006).replace_hour(7),
603    ///     Ok(time!(07:02:03.004_005_006))
604    /// );
605    /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
606    /// ```
607    #[must_use = "This method does not mutate the original `Time`."]
608    pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
609        self.hour = ensure_ranged!(Hours: hour);
610        Ok(self)
611    }
612
613    /// Replace the minutes within the hour.
614    ///
615    /// ```rust
616    /// # use time_macros::time;
617    /// assert_eq!(
618    ///     time!(01:02:03.004_005_006).replace_minute(7),
619    ///     Ok(time!(01:07:03.004_005_006))
620    /// );
621    /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
622    /// ```
623    #[must_use = "This method does not mutate the original `Time`."]
624    pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
625        self.minute = ensure_ranged!(Minutes: minute);
626        Ok(self)
627    }
628
629    /// Replace the seconds within the minute.
630    ///
631    /// ```rust
632    /// # use time_macros::time;
633    /// assert_eq!(
634    ///     time!(01:02:03.004_005_006).replace_second(7),
635    ///     Ok(time!(01:02:07.004_005_006))
636    /// );
637    /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
638    /// ```
639    #[must_use = "This method does not mutate the original `Time`."]
640    pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
641        self.second = ensure_ranged!(Seconds: second);
642        Ok(self)
643    }
644
645    /// Replace the milliseconds within the second.
646    ///
647    /// ```rust
648    /// # use time_macros::time;
649    /// assert_eq!(
650    ///     time!(01:02:03.004_005_006).replace_millisecond(7),
651    ///     Ok(time!(01:02:03.007))
652    /// );
653    /// assert!(time!(01:02:03.004_005_006)
654    ///     .replace_millisecond(1_000)
655    ///     .is_err()); // 1_000 isn't a valid millisecond
656    /// ```
657    #[must_use = "This method does not mutate the original `Time`."]
658    pub const fn replace_millisecond(
659        mut self,
660        millisecond: u16,
661    ) -> Result<Self, error::ComponentRange> {
662        self.nanosecond =
663            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond));
664        Ok(self)
665    }
666
667    /// Replace the microseconds within the second.
668    ///
669    /// ```rust
670    /// # use time_macros::time;
671    /// assert_eq!(
672    ///     time!(01:02:03.004_005_006).replace_microsecond(7_008),
673    ///     Ok(time!(01:02:03.007_008))
674    /// );
675    /// assert!(time!(01:02:03.004_005_006)
676    ///     .replace_microsecond(1_000_000)
677    ///     .is_err()); // 1_000_000 isn't a valid microsecond
678    /// ```
679    #[must_use = "This method does not mutate the original `Time`."]
680    pub const fn replace_microsecond(
681        mut self,
682        microsecond: u32,
683    ) -> Result<Self, error::ComponentRange> {
684        self.nanosecond =
685            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32);
686        Ok(self)
687    }
688
689    /// Replace the nanoseconds within the second.
690    ///
691    /// ```rust
692    /// # use time_macros::time;
693    /// assert_eq!(
694    ///     time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
695    ///     Ok(time!(01:02:03.007_008_009))
696    /// );
697    /// assert!(time!(01:02:03.004_005_006)
698    ///     .replace_nanosecond(1_000_000_000)
699    ///     .is_err()); // 1_000_000_000 isn't a valid nanosecond
700    /// ```
701    #[must_use = "This method does not mutate the original `Time`."]
702    pub const fn replace_nanosecond(
703        mut self,
704        nanosecond: u32,
705    ) -> Result<Self, error::ComponentRange> {
706        self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
707        Ok(self)
708    }
709    // endregion replacement
710}
711
712// region: formatting & parsing
713#[cfg(feature = "formatting")]
714impl Time {
715    /// Format the `Time` using the provided [format description](crate::format_description).
716    pub fn format_into(
717        self,
718        output: &mut (impl io::Write + ?Sized),
719        format: &(impl Formattable + ?Sized),
720    ) -> Result<usize, error::Format> {
721        format.format_into(output, None, Some(self), None)
722    }
723
724    /// Format the `Time` using the provided [format description](crate::format_description).
725    ///
726    /// ```rust
727    /// # use time::format_description;
728    /// # use time_macros::time;
729    /// let format = format_description::parse("[hour]:[minute]:[second]")?;
730    /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
731    /// # Ok::<_, time::Error>(())
732    /// ```
733    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
734        format.format(None, Some(self), None)
735    }
736}
737
738#[cfg(feature = "parsing")]
739impl Time {
740    /// Parse a `Time` from the input using the provided [format
741    /// description](crate::format_description).
742    ///
743    /// ```rust
744    /// # use time::Time;
745    /// # use time_macros::{time, format_description};
746    /// let format = format_description!("[hour]:[minute]:[second]");
747    /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
748    /// # Ok::<_, time::Error>(())
749    /// ```
750    pub fn parse(
751        input: &str,
752        description: &(impl Parsable + ?Sized),
753    ) -> Result<Self, error::Parse> {
754        description.parse_time(input.as_bytes())
755    }
756}
757
758mod private {
759    #[non_exhaustive]
760    #[derive(Debug, Clone, Copy)]
761    pub struct TimeMetadata {
762        /// How many characters wide the formatted subsecond is.
763        pub(super) subsecond_width: u8,
764        /// The value to use when formatting the subsecond. Leading zeroes will be added as
765        /// necessary.
766        pub(super) subsecond_value: u32,
767    }
768}
769use private::TimeMetadata;
770
771impl SmartDisplay for Time {
772    type Metadata = TimeMetadata;
773
774    fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
775        let (subsecond_value, subsecond_width) = match self.nanosecond() {
776            nanos if nanos % 10 != 0 => (nanos, 9),
777            nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
778            nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
779            nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
780            nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
781            nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
782            nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
783            nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
784            nanos => (nanos / 100_000_000, 1),
785        };
786
787        let formatted_width = smart_display::padded_width_of!(
788            self.hour.get(),
789            ":",
790            self.minute.get() => width(2) fill('0'),
791            ":",
792            self.second.get() => width(2) fill('0'),
793            ".",
794        ) + subsecond_width;
795
796        Metadata::new(
797            formatted_width,
798            self,
799            TimeMetadata {
800                subsecond_width: subsecond_width.truncate(),
801                subsecond_value,
802            },
803        )
804    }
805
806    fn fmt_with_metadata(
807        &self,
808        f: &mut fmt::Formatter<'_>,
809        metadata: Metadata<Self>,
810    ) -> fmt::Result {
811        let subsecond_width = metadata.subsecond_width.extend();
812        let subsecond_value = metadata.subsecond_value;
813
814        f.pad_with_width(
815            metadata.unpadded_width(),
816            format_args!(
817                "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
818                self.hour, self.minute, self.second
819            ),
820        )
821    }
822}
823
824impl fmt::Display for Time {
825    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
826        SmartDisplay::fmt(self, f)
827    }
828}
829
830impl fmt::Debug for Time {
831    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
832        fmt::Display::fmt(self, f)
833    }
834}
835// endregion formatting & parsing
836
837// region: trait impls
838impl Add<Duration> for Time {
839    type Output = Self;
840
841    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
842    ///
843    /// ```rust
844    /// # use time::ext::NumericalDuration;
845    /// # use time_macros::time;
846    /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
847    /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
848    /// ```
849    fn add(self, duration: Duration) -> Self::Output {
850        self.adjusting_add(duration).1
851    }
852}
853
854impl Add<StdDuration> for Time {
855    type Output = Self;
856
857    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
858    ///
859    /// ```rust
860    /// # use time::ext::NumericalStdDuration;
861    /// # use time_macros::time;
862    /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
863    /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
864    /// ```
865    fn add(self, duration: StdDuration) -> Self::Output {
866        self.adjusting_add_std(duration).1
867    }
868}
869
870impl_add_assign!(Time: Duration, StdDuration);
871
872impl Sub<Duration> for Time {
873    type Output = Self;
874
875    /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
876    ///
877    /// ```rust
878    /// # use time::ext::NumericalDuration;
879    /// # use time_macros::time;
880    /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
881    /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
882    /// ```
883    fn sub(self, duration: Duration) -> Self::Output {
884        self.adjusting_sub(duration).1
885    }
886}
887
888impl Sub<StdDuration> for Time {
889    type Output = Self;
890
891    /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
892    ///
893    /// ```rust
894    /// # use time::ext::NumericalStdDuration;
895    /// # use time_macros::time;
896    /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
897    /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
898    /// ```
899    fn sub(self, duration: StdDuration) -> Self::Output {
900        self.adjusting_sub_std(duration).1
901    }
902}
903
904impl_sub_assign!(Time: Duration, StdDuration);
905
906impl Sub for Time {
907    type Output = Duration;
908
909    /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
910    /// the same calendar day.
911    ///
912    /// ```rust
913    /// # use time::ext::NumericalDuration;
914    /// # use time_macros::time;
915    /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
916    /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
917    /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
918    /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
919    /// ```
920    fn sub(self, rhs: Self) -> Self::Output {
921        let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
922        let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
923        let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
924        let nanosecond_diff =
925            self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
926
927        let seconds = hour_diff.extend::<i64>() * Second::per(Hour).cast_signed().extend::<i64>()
928            + minute_diff.extend::<i64>() * Second::per(Minute).cast_signed().extend::<i64>()
929            + second_diff.extend::<i64>();
930
931        let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
932            (
933                seconds - 1,
934                nanosecond_diff + Nanosecond::per(Second).cast_signed(),
935            )
936        } else if seconds < 0 && nanosecond_diff > 0 {
937            (
938                seconds + 1,
939                nanosecond_diff - Nanosecond::per(Second).cast_signed(),
940            )
941        } else {
942            (seconds, nanosecond_diff)
943        };
944
945        // Safety: `nanoseconds` is in range due to the overflow handling.
946        unsafe { Duration::new_unchecked(seconds, nanoseconds) }
947    }
948}
949// endregion trait impls