time/
time.rs

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