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    /// 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(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(Microsecond) as u32),
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(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(Microsecond) as u32,
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(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(Microsecond) as u32
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    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
456    /// the date is different.
457    pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
458        let mut nanoseconds = self.nanosecond.get() as i32 + duration.subsec_nanoseconds();
459        let mut seconds =
460            self.second.get() as i8 + (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
461        let mut minutes =
462            self.minute.get() as i8 + (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
463        let mut hours =
464            self.hour.get() as i8 + (duration.whole_hours() % Hour::per(Day) as i64) as i8;
465        let mut date_adjustment = DateAdjustment::None;
466
467        cascade!(nanoseconds in 0..Nanosecond::per(Second) as i32 => seconds);
468        cascade!(seconds in 0..Second::per(Minute) as i8 => minutes);
469        cascade!(minutes in 0..Minute::per(Hour) as i8 => hours);
470        if hours >= Hour::per(Day) as i8 {
471            hours -= Hour::per(Day) as i8;
472            date_adjustment = DateAdjustment::Next;
473        } else if hours < 0 {
474            hours += Hour::per(Day) as i8;
475            date_adjustment = DateAdjustment::Previous;
476        }
477
478        (
479            date_adjustment,
480            // Safety: The cascades above ensure the values are in range.
481            unsafe {
482                Self::__from_hms_nanos_unchecked(
483                    hours as u8,
484                    minutes as u8,
485                    seconds as u8,
486                    nanoseconds as u32,
487                )
488            },
489        )
490    }
491
492    /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
493    /// whether the date is different.
494    pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
495        let mut nanoseconds = self.nanosecond.get() as i32 - duration.subsec_nanoseconds();
496        let mut seconds =
497            self.second.get() as i8 - (duration.whole_seconds() % Second::per(Minute) as i64) as i8;
498        let mut minutes =
499            self.minute.get() as i8 - (duration.whole_minutes() % Minute::per(Hour) as i64) as i8;
500        let mut hours =
501            self.hour.get() as i8 - (duration.whole_hours() % Hour::per(Day) as i64) as i8;
502        let mut date_adjustment = DateAdjustment::None;
503
504        cascade!(nanoseconds in 0..Nanosecond::per(Second) as i32 => seconds);
505        cascade!(seconds in 0..Second::per(Minute) as i8 => minutes);
506        cascade!(minutes in 0..Minute::per(Hour) as i8 => hours);
507        if hours >= Hour::per(Day) as i8 {
508            hours -= Hour::per(Day) as i8;
509            date_adjustment = DateAdjustment::Next;
510        } else if hours < 0 {
511            hours += Hour::per(Day) as i8;
512            date_adjustment = DateAdjustment::Previous;
513        }
514
515        (
516            date_adjustment,
517            // Safety: The cascades above ensure the values are in range.
518            unsafe {
519                Self::__from_hms_nanos_unchecked(
520                    hours as u8,
521                    minutes as u8,
522                    seconds as u8,
523                    nanoseconds as u32,
524                )
525            },
526        )
527    }
528
529    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
530    /// returning whether the date is the previous date as the first element of the tuple.
531    pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
532        let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
533        let mut second =
534            self.second.get() + (duration.as_secs() % Second::per(Minute) as u64) as u8;
535        let mut minute = self.minute.get()
536            + ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as u8;
537        let mut hour = self.hour.get()
538            + ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as u8;
539        let mut is_next_day = false;
540
541        cascade!(nanosecond in 0..Nanosecond::per(Second) => second);
542        cascade!(second in 0..Second::per(Minute) => minute);
543        cascade!(minute in 0..Minute::per(Hour) => hour);
544        if hour >= Hour::per(Day) {
545            hour -= Hour::per(Day);
546            is_next_day = true;
547        }
548
549        (
550            is_next_day,
551            // Safety: The cascades above ensure the values are in range.
552            unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
553        )
554    }
555
556    /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
557    /// returning whether the date is the previous date as the first element of the tuple.
558    pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
559        let mut nanosecond = self.nanosecond.get() as i32 - duration.subsec_nanos() as i32;
560        let mut second =
561            self.second.get() as i8 - (duration.as_secs() % Second::per(Minute) as u64) as i8;
562        let mut minute = self.minute.get() as i8
563            - ((duration.as_secs() / Second::per(Minute) as u64) % Minute::per(Hour) as u64) as i8;
564        let mut hour = self.hour.get() as i8
565            - ((duration.as_secs() / Second::per(Hour) as u64) % Hour::per(Day) as u64) as i8;
566        let mut is_previous_day = false;
567
568        cascade!(nanosecond in 0..Nanosecond::per(Second) as i32 => second);
569        cascade!(second in 0..Second::per(Minute) as i8 => minute);
570        cascade!(minute in 0..Minute::per(Hour) as i8 => hour);
571        if hour < 0 {
572            hour += Hour::per(Day) as i8;
573            is_previous_day = true;
574        }
575
576        (
577            is_previous_day,
578            // Safety: The cascades above ensure the values are in range.
579            unsafe {
580                Self::__from_hms_nanos_unchecked(
581                    hour as u8,
582                    minute as u8,
583                    second as u8,
584                    nanosecond as u32,
585                )
586            },
587        )
588    }
589
590    /// Replace the clock hour.
591    ///
592    /// ```rust
593    /// # use time_macros::time;
594    /// assert_eq!(
595    ///     time!(01:02:03.004_005_006).replace_hour(7),
596    ///     Ok(time!(07:02:03.004_005_006))
597    /// );
598    /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
599    /// ```
600    #[must_use = "This method does not mutate the original `Time`."]
601    pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
602        self.hour = ensure_ranged!(Hours: hour);
603        Ok(self)
604    }
605
606    /// Replace the minutes within the hour.
607    ///
608    /// ```rust
609    /// # use time_macros::time;
610    /// assert_eq!(
611    ///     time!(01:02:03.004_005_006).replace_minute(7),
612    ///     Ok(time!(01:07:03.004_005_006))
613    /// );
614    /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
615    /// ```
616    #[must_use = "This method does not mutate the original `Time`."]
617    pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
618        self.minute = ensure_ranged!(Minutes: minute);
619        Ok(self)
620    }
621
622    /// Replace the seconds within the minute.
623    ///
624    /// ```rust
625    /// # use time_macros::time;
626    /// assert_eq!(
627    ///     time!(01:02:03.004_005_006).replace_second(7),
628    ///     Ok(time!(01:02:07.004_005_006))
629    /// );
630    /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
631    /// ```
632    #[must_use = "This method does not mutate the original `Time`."]
633    pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
634        self.second = ensure_ranged!(Seconds: second);
635        Ok(self)
636    }
637
638    /// Replace the milliseconds within the second.
639    ///
640    /// ```rust
641    /// # use time_macros::time;
642    /// assert_eq!(
643    ///     time!(01:02:03.004_005_006).replace_millisecond(7),
644    ///     Ok(time!(01:02:03.007))
645    /// );
646    /// assert!(time!(01:02:03.004_005_006)
647    ///     .replace_millisecond(1_000)
648    ///     .is_err()); // 1_000 isn't a valid millisecond
649    /// ```
650    #[must_use = "This method does not mutate the original `Time`."]
651    pub const fn replace_millisecond(
652        mut self,
653        millisecond: u16,
654    ) -> Result<Self, error::ComponentRange> {
655        self.nanosecond =
656            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per(Millisecond));
657        Ok(self)
658    }
659
660    /// Replace the microseconds within the second.
661    ///
662    /// ```rust
663    /// # use time_macros::time;
664    /// assert_eq!(
665    ///     time!(01:02:03.004_005_006).replace_microsecond(7_008),
666    ///     Ok(time!(01:02:03.007_008))
667    /// );
668    /// assert!(time!(01:02:03.004_005_006)
669    ///     .replace_microsecond(1_000_000)
670    ///     .is_err()); // 1_000_000 isn't a valid microsecond
671    /// ```
672    #[must_use = "This method does not mutate the original `Time`."]
673    pub const fn replace_microsecond(
674        mut self,
675        microsecond: u32,
676    ) -> Result<Self, error::ComponentRange> {
677        self.nanosecond =
678            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per(Microsecond) as u32);
679        Ok(self)
680    }
681
682    /// Replace the nanoseconds within the second.
683    ///
684    /// ```rust
685    /// # use time_macros::time;
686    /// assert_eq!(
687    ///     time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
688    ///     Ok(time!(01:02:03.007_008_009))
689    /// );
690    /// assert!(time!(01:02:03.004_005_006)
691    ///     .replace_nanosecond(1_000_000_000)
692    ///     .is_err()); // 1_000_000_000 isn't a valid nanosecond
693    /// ```
694    #[must_use = "This method does not mutate the original `Time`."]
695    pub const fn replace_nanosecond(
696        mut self,
697        nanosecond: u32,
698    ) -> Result<Self, error::ComponentRange> {
699        self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
700        Ok(self)
701    }
702}
703
704#[cfg(feature = "formatting")]
705impl Time {
706    /// Format the `Time` using the provided [format description](crate::format_description).
707    pub fn format_into(
708        self,
709        output: &mut (impl io::Write + ?Sized),
710        format: &(impl Formattable + ?Sized),
711    ) -> Result<usize, error::Format> {
712        format.format_into(output, None, Some(self), None)
713    }
714
715    /// Format the `Time` using the provided [format description](crate::format_description).
716    ///
717    /// ```rust
718    /// # use time::format_description;
719    /// # use time_macros::time;
720    /// let format = format_description::parse("[hour]:[minute]:[second]")?;
721    /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
722    /// # Ok::<_, time::Error>(())
723    /// ```
724    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
725        format.format(None, Some(self), None)
726    }
727}
728
729#[cfg(feature = "parsing")]
730impl Time {
731    /// Parse a `Time` from the input using the provided [format
732    /// description](crate::format_description).
733    ///
734    /// ```rust
735    /// # use time::Time;
736    /// # use time_macros::{time, format_description};
737    /// let format = format_description!("[hour]:[minute]:[second]");
738    /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
739    /// # Ok::<_, time::Error>(())
740    /// ```
741    pub fn parse(
742        input: &str,
743        description: &(impl Parsable + ?Sized),
744    ) -> Result<Self, error::Parse> {
745        description.parse_time(input.as_bytes())
746    }
747}
748
749mod private {
750    #[non_exhaustive]
751    #[derive(Debug, Clone, Copy)]
752    pub struct TimeMetadata {
753        /// How many characters wide the formatted subsecond is.
754        pub(super) subsecond_width: u8,
755        /// The value to use when formatting the subsecond. Leading zeroes will be added as
756        /// necessary.
757        pub(super) subsecond_value: u32,
758    }
759}
760use private::TimeMetadata;
761
762impl SmartDisplay for Time {
763    type Metadata = TimeMetadata;
764
765    fn metadata(&self, _: FormatterOptions) -> Metadata<Self> {
766        let (subsecond_value, subsecond_width) = match self.nanosecond() {
767            nanos if nanos % 10 != 0 => (nanos, 9),
768            nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
769            nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
770            nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
771            nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
772            nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
773            nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
774            nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
775            nanos => (nanos / 100_000_000, 1),
776        };
777
778        let formatted_width = smart_display::padded_width_of!(
779            self.hour.get(),
780            ":",
781            self.minute.get() => width(2) fill('0'),
782            ":",
783            self.second.get() => width(2) fill('0'),
784            ".",
785        ) + subsecond_width;
786
787        Metadata::new(
788            formatted_width,
789            self,
790            TimeMetadata {
791                subsecond_width: subsecond_width.truncate(),
792                subsecond_value,
793            },
794        )
795    }
796
797    fn fmt_with_metadata(
798        &self,
799        f: &mut fmt::Formatter<'_>,
800        metadata: Metadata<Self>,
801    ) -> fmt::Result {
802        let subsecond_width = metadata.subsecond_width.extend();
803        let subsecond_value = metadata.subsecond_value;
804
805        f.pad_with_width(
806            metadata.unpadded_width(),
807            format_args!(
808                "{}:{:02}:{:02}.{subsecond_value:0subsecond_width$}",
809                self.hour, self.minute, self.second
810            ),
811        )
812    }
813}
814
815impl fmt::Display for Time {
816    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
817        SmartDisplay::fmt(self, f)
818    }
819}
820
821impl fmt::Debug for Time {
822    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
823        fmt::Display::fmt(self, f)
824    }
825}
826
827impl Add<Duration> for Time {
828    type Output = Self;
829
830    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
831    ///
832    /// ```rust
833    /// # use time::ext::NumericalDuration;
834    /// # use time_macros::time;
835    /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
836    /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
837    /// ```
838    fn add(self, duration: Duration) -> Self::Output {
839        self.adjusting_add(duration).1
840    }
841}
842
843impl Add<StdDuration> for Time {
844    type Output = Self;
845
846    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
847    ///
848    /// ```rust
849    /// # use time::ext::NumericalStdDuration;
850    /// # use time_macros::time;
851    /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
852    /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
853    /// ```
854    fn add(self, duration: StdDuration) -> Self::Output {
855        self.adjusting_add_std(duration).1
856    }
857}
858
859impl_add_assign!(Time: Duration, StdDuration);
860
861impl Sub<Duration> for Time {
862    type Output = Self;
863
864    /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
865    ///
866    /// ```rust
867    /// # use time::ext::NumericalDuration;
868    /// # use time_macros::time;
869    /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
870    /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
871    /// ```
872    fn sub(self, duration: Duration) -> Self::Output {
873        self.adjusting_sub(duration).1
874    }
875}
876
877impl Sub<StdDuration> for Time {
878    type Output = Self;
879
880    /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
881    ///
882    /// ```rust
883    /// # use time::ext::NumericalStdDuration;
884    /// # use time_macros::time;
885    /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
886    /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
887    /// ```
888    fn sub(self, duration: StdDuration) -> Self::Output {
889        self.adjusting_sub_std(duration).1
890    }
891}
892
893impl_sub_assign!(Time: Duration, StdDuration);
894
895impl Sub for Time {
896    type Output = Duration;
897
898    /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
899    /// the same calendar day.
900    ///
901    /// ```rust
902    /// # use time::ext::NumericalDuration;
903    /// # use time_macros::time;
904    /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
905    /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
906    /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
907    /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
908    /// ```
909    fn sub(self, rhs: Self) -> Self::Output {
910        let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
911        let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
912        let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
913        let nanosecond_diff =
914            self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
915
916        let seconds = hour_diff.extend::<i64>() * Second::per(Hour).cast_signed().extend::<i64>()
917            + minute_diff.extend::<i64>() * Second::per(Minute).cast_signed().extend::<i64>()
918            + second_diff.extend::<i64>();
919
920        let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
921            (
922                seconds - 1,
923                nanosecond_diff + Nanosecond::per(Second).cast_signed(),
924            )
925        } else if seconds < 0 && nanosecond_diff > 0 {
926            (
927                seconds + 1,
928                nanosecond_diff - Nanosecond::per(Second).cast_signed(),
929            )
930        } else {
931            (seconds, nanosecond_diff)
932        };
933
934        // Safety: `nanoseconds` is in range due to the overflow handling.
935        unsafe { Duration::new_unchecked(seconds, nanoseconds) }
936    }
937}