Skip to main content

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::mem::MaybeUninit;
8use core::ops::{Add, AddAssign, Sub, SubAssign};
9use core::time::Duration as StdDuration;
10use core::{fmt, hint};
11#[cfg(feature = "formatting")]
12use std::io;
13
14use deranged::{ru8, ru32};
15use num_conv::prelude::*;
16use powerfmt::smart_display::{FormatterOptions, Metadata, SmartDisplay};
17
18#[cfg(feature = "formatting")]
19use crate::formatting::Formattable;
20use crate::internal_macros::{cascade, ensure_ranged};
21use crate::num_fmt::{
22    one_to_two_digits_no_padding, str_from_raw_parts, truncated_subsecond_from_nanos,
23    two_digits_zero_padded,
24};
25#[cfg(feature = "parsing")]
26use crate::parsing::Parsable;
27use crate::unit::*;
28use crate::util::DateAdjustment;
29use crate::{Duration, error};
30
31/// By explicitly inserting this enum where padding is expected, the compiler is able to better
32/// perform niche value optimization.
33#[repr(u8)]
34#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
35pub(crate) enum Padding {
36    #[allow(clippy::missing_docs_in_private_items)]
37    Optimize,
38}
39
40/// The type of the `hour` field of `Time`.
41pub(crate) type Hours = ru8<0, { Hour::per_t::<u8>(Day) - 1 }>;
42/// The type of the `minute` field of `Time`.
43pub(crate) type Minutes = ru8<0, { Minute::per_t::<u8>(Hour) - 1 }>;
44/// The type of the `second` field of `Time`.
45pub(crate) type Seconds = ru8<0, { Second::per_t::<u8>(Minute) - 1 }>;
46/// The type of the `nanosecond` field of `Time`.
47pub(crate) type Nanoseconds = ru32<0, { Nanosecond::per_t::<u32>(Second) - 1 }>;
48
49/// The clock time within a given date. Nanosecond precision.
50///
51/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
52/// (either positive or negative).
53///
54/// When comparing two `Time`s, they are assumed to be in the same calendar date.
55#[derive(Clone, Copy, Eq)]
56#[cfg_attr(not(docsrs), repr(C))]
57pub struct Time {
58    // The order of this struct's fields matter! Do not reorder them.
59
60    // Little endian version
61    #[cfg(target_endian = "little")]
62    nanosecond: Nanoseconds,
63    #[cfg(target_endian = "little")]
64    second: Seconds,
65    #[cfg(target_endian = "little")]
66    minute: Minutes,
67    #[cfg(target_endian = "little")]
68    hour: Hours,
69    #[cfg(target_endian = "little")]
70    padding: Padding,
71
72    // Big endian version
73    #[cfg(target_endian = "big")]
74    padding: Padding,
75    #[cfg(target_endian = "big")]
76    hour: Hours,
77    #[cfg(target_endian = "big")]
78    minute: Minutes,
79    #[cfg(target_endian = "big")]
80    second: Seconds,
81    #[cfg(target_endian = "big")]
82    nanosecond: Nanoseconds,
83}
84
85impl Hash for Time {
86    #[inline]
87    fn hash<H>(&self, state: &mut H)
88    where
89        H: Hasher,
90    {
91        self.as_u64().hash(state)
92    }
93}
94
95impl PartialEq for Time {
96    #[inline]
97    fn eq(&self, other: &Self) -> bool {
98        self.as_u64().eq(&other.as_u64())
99    }
100}
101
102impl PartialOrd for Time {
103    #[inline]
104    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
105        Some(self.cmp(other))
106    }
107}
108
109impl Ord for Time {
110    #[inline]
111    fn cmp(&self, other: &Self) -> Ordering {
112        self.as_u64().cmp(&other.as_u64())
113    }
114}
115
116impl Time {
117    /// Provide a representation of `Time` as a `u64`. This value can be used for equality, hashing,
118    /// and ordering.
119    #[inline]
120    pub(crate) const fn as_u64(self) -> u64 {
121        // Safety: `self` is presumed valid because it exists, and any value of `u64` is valid. Size
122        // and alignment are enforced by the compiler. There is no implicit padding in either `Time`
123        // or `u64`.
124        unsafe { core::mem::transmute(self) }
125    }
126
127    /// A `Time` that is exactly midnight. This is the smallest possible value for a `Time`.
128    ///
129    /// ```rust
130    /// # use time::Time;
131    /// # use time_macros::time;
132    /// assert_eq!(Time::MIDNIGHT, time!(0:00));
133    /// ```
134    #[doc(alias = "MIN")]
135    pub const MIDNIGHT: Self =
136        Self::from_hms_nanos_ranged(Hours::MIN, Minutes::MIN, Seconds::MIN, Nanoseconds::MIN);
137
138    /// A `Time` that is one nanosecond before midnight. This is the largest possible value for a
139    /// `Time`.
140    ///
141    /// ```rust
142    /// # use time::Time;
143    /// # use time_macros::time;
144    /// assert_eq!(Time::MAX, time!(23:59:59.999_999_999));
145    /// ```
146    pub const MAX: Self =
147        Self::from_hms_nanos_ranged(Hours::MAX, Minutes::MAX, Seconds::MAX, Nanoseconds::MAX);
148
149    /// Create a `Time` from its components.
150    ///
151    /// # Safety
152    ///
153    /// - `hours` must be in the range `0..=23`.
154    /// - `minutes` must be in the range `0..=59`.
155    /// - `seconds` must be in the range `0..=59`.
156    /// - `nanoseconds` must be in the range `0..=999_999_999`.
157    #[doc(hidden)]
158    #[inline]
159    #[track_caller]
160    pub const unsafe fn __from_hms_nanos_unchecked(
161        hour: u8,
162        minute: u8,
163        second: u8,
164        nanosecond: u32,
165    ) -> Self {
166        // Safety: The caller must uphold the safety invariants.
167        unsafe {
168            Self::from_hms_nanos_ranged(
169                Hours::new_unchecked(hour),
170                Minutes::new_unchecked(minute),
171                Seconds::new_unchecked(second),
172                Nanoseconds::new_unchecked(nanosecond),
173            )
174        }
175    }
176
177    /// Attempt to create a `Time` from the hour, minute, and second.
178    ///
179    /// ```rust
180    /// # use time::Time;
181    /// assert!(Time::from_hms(1, 2, 3).is_ok());
182    /// ```
183    ///
184    /// ```rust
185    /// # use time::Time;
186    /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
187    /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
188    /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
189    /// ```
190    #[inline]
191    pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
192        Ok(Self::from_hms_nanos_ranged(
193            ensure_ranged!(Hours: hour),
194            ensure_ranged!(Minutes: minute),
195            ensure_ranged!(Seconds: second),
196            Nanoseconds::MIN,
197        ))
198    }
199
200    /// Create a `Time` from the hour, minute, second, and nanosecond.
201    #[inline]
202    pub(crate) const fn from_hms_nanos_ranged(
203        hour: Hours,
204        minute: Minutes,
205        second: Seconds,
206        nanosecond: Nanoseconds,
207    ) -> Self {
208        Self {
209            hour,
210            minute,
211            second,
212            nanosecond,
213            padding: Padding::Optimize,
214        }
215    }
216
217    /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
218    ///
219    /// ```rust
220    /// # use time::Time;
221    /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
222    /// ```
223    ///
224    /// ```rust
225    /// # use time::Time;
226    /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
227    /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
228    /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
229    /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
230    /// ```
231    #[inline]
232    pub const fn from_hms_milli(
233        hour: u8,
234        minute: u8,
235        second: u8,
236        millisecond: u16,
237    ) -> Result<Self, error::ComponentRange> {
238        Ok(Self::from_hms_nanos_ranged(
239            ensure_ranged!(Hours: hour),
240            ensure_ranged!(Minutes: minute),
241            ensure_ranged!(Seconds: second),
242            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond)),
243        ))
244    }
245
246    /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
247    ///
248    /// ```rust
249    /// # use time::Time;
250    /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
251    /// ```
252    ///
253    /// ```rust
254    /// # use time::Time;
255    /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
256    /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
257    /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
258    /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
259    /// ```
260    #[inline]
261    pub const fn from_hms_micro(
262        hour: u8,
263        minute: u8,
264        second: u8,
265        microsecond: u32,
266    ) -> Result<Self, error::ComponentRange> {
267        Ok(Self::from_hms_nanos_ranged(
268            ensure_ranged!(Hours: hour),
269            ensure_ranged!(Minutes: minute),
270            ensure_ranged!(Seconds: second),
271            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond)),
272        ))
273    }
274
275    /// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
276    ///
277    /// ```rust
278    /// # use time::Time;
279    /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
280    /// ```
281    ///
282    /// ```rust
283    /// # use time::Time;
284    /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
285    /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
286    /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
287    /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
288    /// ```
289    #[inline]
290    pub const fn from_hms_nano(
291        hour: u8,
292        minute: u8,
293        second: u8,
294        nanosecond: u32,
295    ) -> Result<Self, error::ComponentRange> {
296        Ok(Self::from_hms_nanos_ranged(
297            ensure_ranged!(Hours: hour),
298            ensure_ranged!(Minutes: minute),
299            ensure_ranged!(Seconds: second),
300            ensure_ranged!(Nanoseconds: nanosecond),
301        ))
302    }
303
304    /// Get the clock hour, minute, and second.
305    ///
306    /// ```rust
307    /// # use time_macros::time;
308    /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
309    /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
310    /// ```
311    #[inline]
312    pub const fn as_hms(self) -> (u8, u8, u8) {
313        (self.hour.get(), self.minute.get(), self.second.get())
314    }
315
316    /// Get the clock hour, minute, second, and millisecond.
317    ///
318    /// ```rust
319    /// # use time_macros::time;
320    /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
321    /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
322    /// ```
323    #[inline]
324    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
325        (
326            self.hour.get(),
327            self.minute.get(),
328            self.second.get(),
329            (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16,
330        )
331    }
332
333    /// Get the clock hour, minute, second, and microsecond.
334    ///
335    /// ```rust
336    /// # use time_macros::time;
337    /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
338    /// assert_eq!(
339    ///     time!(23:59:59.999_999).as_hms_micro(),
340    ///     (23, 59, 59, 999_999)
341    /// );
342    /// ```
343    #[inline]
344    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
345        (
346            self.hour.get(),
347            self.minute.get(),
348            self.second.get(),
349            self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond),
350        )
351    }
352
353    /// Get the clock hour, minute, second, and nanosecond.
354    ///
355    /// ```rust
356    /// # use time_macros::time;
357    /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
358    /// assert_eq!(
359    ///     time!(23:59:59.999_999_999).as_hms_nano(),
360    ///     (23, 59, 59, 999_999_999)
361    /// );
362    /// ```
363    #[inline]
364    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
365        (
366            self.hour.get(),
367            self.minute.get(),
368            self.second.get(),
369            self.nanosecond.get(),
370        )
371    }
372
373    /// Get the clock hour, minute, second, and nanosecond.
374    #[inline]
375    #[cfg(any(feature = "formatting", 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    #[inline]
390    pub const fn hour(self) -> u8 {
391        self.hour.get()
392    }
393
394    /// Get the minute within the hour.
395    ///
396    /// The returned value will always be in the range `0..60`.
397    ///
398    /// ```rust
399    /// # use time_macros::time;
400    /// assert_eq!(time!(0:00:00).minute(), 0);
401    /// assert_eq!(time!(23:59:59).minute(), 59);
402    /// ```
403    #[inline]
404    pub const fn minute(self) -> u8 {
405        self.minute.get()
406    }
407
408    /// Get the second within the minute.
409    ///
410    /// The returned value will always be in the range `0..60`.
411    ///
412    /// ```rust
413    /// # use time_macros::time;
414    /// assert_eq!(time!(0:00:00).second(), 0);
415    /// assert_eq!(time!(23:59:59).second(), 59);
416    /// ```
417    #[inline]
418    pub const fn second(self) -> u8 {
419        self.second.get()
420    }
421
422    /// Get the milliseconds within the second.
423    ///
424    /// The returned value will always be in the range `0..1_000`.
425    ///
426    /// ```rust
427    /// # use time_macros::time;
428    /// assert_eq!(time!(0:00).millisecond(), 0);
429    /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
430    /// ```
431    #[inline]
432    pub const fn millisecond(self) -> u16 {
433        (self.nanosecond.get() / Nanosecond::per_t::<u32>(Millisecond)) as u16
434    }
435
436    /// Get the microseconds within the second.
437    ///
438    /// The returned value will always be in the range `0..1_000_000`.
439    ///
440    /// ```rust
441    /// # use time_macros::time;
442    /// assert_eq!(time!(0:00).microsecond(), 0);
443    /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
444    /// ```
445    #[inline]
446    pub const fn microsecond(self) -> u32 {
447        self.nanosecond.get() / Nanosecond::per_t::<u32>(Microsecond)
448    }
449
450    /// Get the nanoseconds within the second.
451    ///
452    /// The returned value will always be in the range `0..1_000_000_000`.
453    ///
454    /// ```rust
455    /// # use time_macros::time;
456    /// assert_eq!(time!(0:00).nanosecond(), 0);
457    /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
458    /// ```
459    #[inline]
460    pub const fn nanosecond(self) -> u32 {
461        self.nanosecond.get()
462    }
463
464    /// Determine the [`Duration`] that, if added to `self`, would result in the parameter.
465    ///
466    /// ```rust
467    /// # use time::Time;
468    /// # use time::ext::NumericalDuration;
469    /// # use time_macros::time;
470    /// assert_eq!(time!(18:00).duration_until(Time::MIDNIGHT), 6.hours());
471    /// assert_eq!(time!(23:00).duration_until(time!(1:00)), 2.hours());
472    /// ```
473    #[inline]
474    pub const fn duration_until(self, other: Self) -> Duration {
475        let mut nanoseconds =
476            other.nanosecond.get().cast_signed() - self.nanosecond.get().cast_signed();
477        let seconds = other.second.get().cast_signed() - self.second.get().cast_signed();
478        let minutes = other.minute.get().cast_signed() - self.minute.get().cast_signed();
479        let hours = other.hour.get().cast_signed() - self.hour.get().cast_signed();
480
481        // Safety: For all four variables, the bounds are obviously true given the previous bounds
482        // and nature of subtraction.
483        unsafe {
484            hint::assert_unchecked(
485                nanoseconds
486                    >= Nanoseconds::MIN.get().cast_signed() - Nanoseconds::MAX.get().cast_signed(),
487            );
488            hint::assert_unchecked(
489                nanoseconds
490                    <= Nanoseconds::MAX.get().cast_signed() - Nanoseconds::MIN.get().cast_signed(),
491            );
492            hint::assert_unchecked(
493                seconds >= Seconds::MIN.get().cast_signed() - Seconds::MAX.get().cast_signed(),
494            );
495            hint::assert_unchecked(
496                seconds <= Seconds::MAX.get().cast_signed() - Seconds::MIN.get().cast_signed(),
497            );
498            hint::assert_unchecked(
499                minutes >= Minutes::MIN.get().cast_signed() - Minutes::MAX.get().cast_signed(),
500            );
501            hint::assert_unchecked(
502                minutes <= Minutes::MAX.get().cast_signed() - Minutes::MIN.get().cast_signed(),
503            );
504            hint::assert_unchecked(
505                hours >= Hours::MIN.get().cast_signed() - Hours::MAX.get().cast_signed(),
506            );
507            hint::assert_unchecked(
508                hours <= Hours::MAX.get().cast_signed() - Hours::MIN.get().cast_signed(),
509            );
510        }
511
512        let mut total_seconds = hours as i32 * Second::per_t::<i32>(Hour)
513            + minutes as i32 * Second::per_t::<i32>(Minute)
514            + seconds as i32;
515
516        cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => total_seconds);
517
518        if total_seconds < 0 {
519            total_seconds += Second::per_t::<i32>(Day);
520        }
521
522        // Safety: The range of `nanoseconds` is guaranteed by the cascades above.
523        unsafe { Duration::new_unchecked(total_seconds as i64, nanoseconds) }
524    }
525
526    /// Determine the [`Duration`] that, if added to the parameter, would result in `self`.
527    ///
528    /// ```rust
529    /// # use time::Time;
530    /// # use time::ext::NumericalDuration;
531    /// # use time_macros::time;
532    /// assert_eq!(Time::MIDNIGHT.duration_since(time!(18:00)), 6.hours());
533    /// assert_eq!(time!(1:00).duration_since(time!(23:00)), 2.hours());
534    /// ```
535    #[inline]
536    pub const fn duration_since(self, other: Self) -> Duration {
537        other.duration_until(self)
538    }
539
540    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
541    /// the date is different.
542    #[inline]
543    pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
544        let mut nanoseconds = self.nanosecond.get().cast_signed() + duration.subsec_nanoseconds();
545        let mut seconds = self.second.get().cast_signed()
546            + (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
547        let mut minutes = self.minute.get().cast_signed()
548            + (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
549        let mut hours = self.hour.get().cast_signed()
550            + (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
551        let mut date_adjustment = DateAdjustment::None;
552
553        cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
554        cascade!(seconds in 0..Second::per_t(Minute) => minutes);
555        cascade!(minutes in 0..Minute::per_t(Hour) => hours);
556        if hours >= Hour::per_t(Day) {
557            hours -= Hour::per_t::<i8>(Day);
558            date_adjustment = DateAdjustment::Next;
559        } else if hours < 0 {
560            hours += Hour::per_t::<i8>(Day);
561            date_adjustment = DateAdjustment::Previous;
562        }
563
564        (
565            date_adjustment,
566            // Safety: The cascades above ensure the values are in range.
567            unsafe {
568                Self::__from_hms_nanos_unchecked(
569                    hours.cast_unsigned(),
570                    minutes.cast_unsigned(),
571                    seconds.cast_unsigned(),
572                    nanoseconds.cast_unsigned(),
573                )
574            },
575        )
576    }
577
578    /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
579    /// whether the date is different.
580    #[inline]
581    pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
582        let mut nanoseconds = self.nanosecond.get().cast_signed() - duration.subsec_nanoseconds();
583        let mut seconds = self.second.get().cast_signed()
584            - (duration.whole_seconds() % Second::per_t::<i64>(Minute)) as i8;
585        let mut minutes = self.minute.get().cast_signed()
586            - (duration.whole_minutes() % Minute::per_t::<i64>(Hour)) as i8;
587        let mut hours = self.hour.get().cast_signed()
588            - (duration.whole_hours() % Hour::per_t::<i64>(Day)) as i8;
589        let mut date_adjustment = DateAdjustment::None;
590
591        cascade!(nanoseconds in 0..Nanosecond::per_t(Second) => seconds);
592        cascade!(seconds in 0..Second::per_t(Minute) => minutes);
593        cascade!(minutes in 0..Minute::per_t(Hour) => hours);
594        if hours >= Hour::per_t(Day) {
595            hours -= Hour::per_t::<i8>(Day);
596            date_adjustment = DateAdjustment::Next;
597        } else if hours < 0 {
598            hours += Hour::per_t::<i8>(Day);
599            date_adjustment = DateAdjustment::Previous;
600        }
601
602        (
603            date_adjustment,
604            // Safety: The cascades above ensure the values are in range.
605            unsafe {
606                Self::__from_hms_nanos_unchecked(
607                    hours.cast_unsigned(),
608                    minutes.cast_unsigned(),
609                    seconds.cast_unsigned(),
610                    nanoseconds.cast_unsigned(),
611                )
612            },
613        )
614    }
615
616    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
617    /// returning whether the date is the previous date as the first element of the tuple.
618    #[inline]
619    pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
620        let mut nanosecond = self.nanosecond.get() + duration.subsec_nanos();
621        let mut second =
622            self.second.get() + (duration.as_secs() % Second::per_t::<u64>(Minute)) as u8;
623        let mut minute = self.minute.get()
624            + ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
625                as u8;
626        let mut hour = self.hour.get()
627            + ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as u8;
628        let mut is_next_day = false;
629
630        cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
631        cascade!(second in 0..Second::per_t(Minute) => minute);
632        cascade!(minute in 0..Minute::per_t(Hour) => hour);
633        if hour >= Hour::per_t::<u8>(Day) {
634            hour -= Hour::per_t::<u8>(Day);
635            is_next_day = true;
636        }
637
638        (
639            is_next_day,
640            // Safety: The cascades above ensure the values are in range.
641            unsafe { Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond) },
642        )
643    }
644
645    /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
646    /// returning whether the date is the previous date as the first element of the tuple.
647    #[inline]
648    pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
649        let mut nanosecond =
650            self.nanosecond.get().cast_signed() - duration.subsec_nanos().cast_signed();
651        let mut second = self.second.get().cast_signed()
652            - (duration.as_secs() % Second::per_t::<u64>(Minute)) as i8;
653        let mut minute = self.minute.get().cast_signed()
654            - ((duration.as_secs() / Second::per_t::<u64>(Minute)) % Minute::per_t::<u64>(Hour))
655                as i8;
656        let mut hour = self.hour.get().cast_signed()
657            - ((duration.as_secs() / Second::per_t::<u64>(Hour)) % Hour::per_t::<u64>(Day)) as i8;
658        let mut is_previous_day = false;
659
660        cascade!(nanosecond in 0..Nanosecond::per_t(Second) => second);
661        cascade!(second in 0..Second::per_t(Minute) => minute);
662        cascade!(minute in 0..Minute::per_t(Hour) => hour);
663        if hour < 0 {
664            hour += Hour::per_t::<i8>(Day);
665            is_previous_day = true;
666        }
667
668        (
669            is_previous_day,
670            // Safety: The cascades above ensure the values are in range.
671            unsafe {
672                Self::__from_hms_nanos_unchecked(
673                    hour.cast_unsigned(),
674                    minute.cast_unsigned(),
675                    second.cast_unsigned(),
676                    nanosecond.cast_unsigned(),
677                )
678            },
679        )
680    }
681
682    /// Replace the clock hour.
683    ///
684    /// ```rust
685    /// # use time_macros::time;
686    /// assert_eq!(
687    ///     time!(01:02:03.004_005_006).replace_hour(7),
688    ///     Ok(time!(07:02:03.004_005_006))
689    /// );
690    /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
691    /// ```
692    #[must_use = "This method does not mutate the original `Time`."]
693    #[inline]
694    pub const fn replace_hour(mut self, hour: u8) -> Result<Self, error::ComponentRange> {
695        self.hour = ensure_ranged!(Hours: hour);
696        Ok(self)
697    }
698
699    /// Truncate the time to the hour, setting the minute, second, and subsecond components to zero.
700    ///
701    /// ```rust
702    /// # use time_macros::time;
703    /// assert_eq!(time!(01:02:03.004_005_006).truncate_to_hour(), time!(01:00));
704    /// ```
705    #[must_use = "This method does not mutate the original `Time`."]
706    #[inline]
707    pub const fn truncate_to_hour(mut self) -> Self {
708        self.minute = Minutes::MIN;
709        self.second = Seconds::MIN;
710        self.nanosecond = Nanoseconds::MIN;
711        self
712    }
713
714    /// Replace the minutes within the hour.
715    ///
716    /// ```rust
717    /// # use time_macros::time;
718    /// assert_eq!(
719    ///     time!(01:02:03.004_005_006).replace_minute(7),
720    ///     Ok(time!(01:07:03.004_005_006))
721    /// );
722    /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
723    /// ```
724    #[must_use = "This method does not mutate the original `Time`."]
725    #[inline]
726    pub const fn replace_minute(mut self, minute: u8) -> Result<Self, error::ComponentRange> {
727        self.minute = ensure_ranged!(Minutes: minute);
728        Ok(self)
729    }
730
731    /// Truncate the time to the minute, setting the second and subsecond components to zero.
732    ///
733    /// ```rust
734    /// # use time_macros::time;
735    /// assert_eq!(
736    ///     time!(01:02:03.004_005_006).truncate_to_minute(),
737    ///     time!(01:02)
738    /// );
739    /// ```
740    #[must_use = "This method does not mutate the original `Time`."]
741    #[inline]
742    pub const fn truncate_to_minute(mut self) -> Self {
743        self.second = Seconds::MIN;
744        self.nanosecond = Nanoseconds::MIN;
745        self
746    }
747
748    /// Replace the seconds within the minute.
749    ///
750    /// ```rust
751    /// # use time_macros::time;
752    /// assert_eq!(
753    ///     time!(01:02:03.004_005_006).replace_second(7),
754    ///     Ok(time!(01:02:07.004_005_006))
755    /// );
756    /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
757    /// ```
758    #[must_use = "This method does not mutate the original `Time`."]
759    #[inline]
760    pub const fn replace_second(mut self, second: u8) -> Result<Self, error::ComponentRange> {
761        self.second = ensure_ranged!(Seconds: second);
762        Ok(self)
763    }
764
765    /// Truncate the time to the second, setting the subsecond component to zero.
766    ///
767    /// ```rust
768    /// # use time_macros::time;
769    /// assert_eq!(
770    ///     time!(01:02:03.004_005_006).truncate_to_second(),
771    ///     time!(01:02:03)
772    /// );
773    /// ```
774    #[must_use = "This method does not mutate the original `Time`."]
775    #[inline]
776    pub const fn truncate_to_second(mut self) -> Self {
777        self.nanosecond = Nanoseconds::MIN;
778        self
779    }
780
781    /// Replace the milliseconds within the second.
782    ///
783    /// ```rust
784    /// # use time_macros::time;
785    /// assert_eq!(
786    ///     time!(01:02:03.004_005_006).replace_millisecond(7),
787    ///     Ok(time!(01:02:03.007))
788    /// );
789    /// assert!(
790    ///     time!(01:02:03.004_005_006)
791    ///         .replace_millisecond(1_000)
792    ///         .is_err() // 1_000 isn't a valid millisecond
793    /// );
794    /// ```
795    #[must_use = "This method does not mutate the original `Time`."]
796    #[inline]
797    pub const fn replace_millisecond(
798        mut self,
799        millisecond: u16,
800    ) -> Result<Self, error::ComponentRange> {
801        self.nanosecond =
802            ensure_ranged!(Nanoseconds: millisecond as u32 * Nanosecond::per_t::<u32>(Millisecond));
803        Ok(self)
804    }
805
806    /// Truncate the time to the millisecond, setting the microsecond and nanosecond components to
807    /// zero.
808    ///
809    /// ```rust
810    /// # use time_macros::time;
811    /// assert_eq!(
812    ///     time!(01:02:03.004_005_006).truncate_to_millisecond(),
813    ///     time!(01:02:03.004)
814    /// );
815    /// ```
816    #[must_use = "This method does not mutate the original `Time`."]
817    #[inline]
818    pub const fn truncate_to_millisecond(mut self) -> Self {
819        // Safety: Truncating to the millisecond will always produce a valid nanosecond.
820        self.nanosecond = unsafe {
821            Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000_000))
822        };
823        self
824    }
825
826    /// Replace the microseconds within the second.
827    ///
828    /// ```rust
829    /// # use time_macros::time;
830    /// assert_eq!(
831    ///     time!(01:02:03.004_005_006).replace_microsecond(7_008),
832    ///     Ok(time!(01:02:03.007_008))
833    /// );
834    /// assert!(
835    ///     time!(01:02:03.004_005_006)
836    ///         .replace_microsecond(1_000_000)
837    ///         .is_err() // 1_000_000 isn't a valid microsecond
838    /// );
839    /// ```
840    #[must_use = "This method does not mutate the original `Time`."]
841    #[inline]
842    pub const fn replace_microsecond(
843        mut self,
844        microsecond: u32,
845    ) -> Result<Self, error::ComponentRange> {
846        self.nanosecond =
847            ensure_ranged!(Nanoseconds: microsecond * Nanosecond::per_t::<u32>(Microsecond));
848        Ok(self)
849    }
850
851    /// Truncate the time to the microsecond, setting the nanosecond component to zero.
852    ///
853    /// ```rust
854    /// # use time_macros::time;
855    /// assert_eq!(
856    ///     time!(01:02:03.004_005_006).truncate_to_microsecond(),
857    ///     time!(01:02:03.004_005)
858    /// );
859    /// ```
860    #[must_use = "This method does not mutate the original `Time`."]
861    #[inline]
862    pub const fn truncate_to_microsecond(mut self) -> Self {
863        // Safety: Truncating to the microsecond will always produce a valid nanosecond.
864        self.nanosecond = unsafe {
865            Nanoseconds::new_unchecked(self.nanosecond.get() - (self.nanosecond.get() % 1_000))
866        };
867        self
868    }
869
870    /// Replace the nanoseconds within the second.
871    ///
872    /// ```rust
873    /// # use time_macros::time;
874    /// assert_eq!(
875    ///     time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
876    ///     Ok(time!(01:02:03.007_008_009))
877    /// );
878    /// assert!(
879    ///     time!(01:02:03.004_005_006)
880    ///         .replace_nanosecond(1_000_000_000)
881    ///         .is_err() // 1_000_000_000 isn't a valid nanosecond
882    /// );
883    /// ```
884    #[must_use = "This method does not mutate the original `Time`."]
885    #[inline]
886    pub const fn replace_nanosecond(
887        mut self,
888        nanosecond: u32,
889    ) -> Result<Self, error::ComponentRange> {
890        self.nanosecond = ensure_ranged!(Nanoseconds: nanosecond);
891        Ok(self)
892    }
893}
894
895#[cfg(feature = "formatting")]
896impl Time {
897    /// Format the `Time` using the provided [format description](crate::format_description).
898    #[inline]
899    pub fn format_into(
900        self,
901        output: &mut (impl io::Write + ?Sized),
902        format: &(impl Formattable + ?Sized),
903    ) -> Result<usize, error::Format> {
904        format.format_into(output, &self, &mut Default::default())
905    }
906
907    /// Format the `Time` using the provided [format description](crate::format_description).
908    ///
909    /// ```rust
910    /// # use time::format_description;
911    /// # use time_macros::time;
912    /// let format = format_description::parse("[hour]:[minute]:[second]")?;
913    /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
914    /// # Ok::<_, time::Error>(())
915    /// ```
916    #[inline]
917    pub fn format(self, format: &(impl Formattable + ?Sized)) -> Result<String, error::Format> {
918        format.format(&self, &mut Default::default())
919    }
920}
921
922#[cfg(feature = "parsing")]
923impl Time {
924    /// Parse a `Time` from the input using the provided [format
925    /// description](crate::format_description).
926    ///
927    /// ```rust
928    /// # use time::Time;
929    /// # use time_macros::{time, format_description};
930    /// let format = format_description!("[hour]:[minute]:[second]");
931    /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
932    /// # Ok::<_, time::Error>(())
933    /// ```
934    #[inline]
935    pub fn parse(
936        input: &str,
937        description: &(impl Parsable + ?Sized),
938    ) -> Result<Self, error::Parse> {
939        description.parse_time(input.as_bytes())
940    }
941}
942
943mod private {
944    /// Metadata for `Time`.
945    #[non_exhaustive]
946    #[derive(Debug)]
947    pub struct TimeMetadata;
948}
949use private::TimeMetadata;
950
951// This no longer needs special handling, as the format is fixed and doesn't require anything
952// advanced. Trait impls can't be deprecated and the info is still useful for other types
953// implementing `SmartDisplay`, so leave it as-is for now.
954impl SmartDisplay for Time {
955    type Metadata = TimeMetadata;
956
957    #[inline]
958    fn metadata(&self, _: FormatterOptions) -> Metadata<'_, Self> {
959        let hour_width = if self.hour() < 10 { 1 } else { 2 };
960        let subsecond_width = match self.nanosecond() {
961            nanos if nanos % 10 != 0 => 9,
962            nanos if (nanos / 10) % 10 != 0 => 8,
963            nanos if (nanos / 100) % 10 != 0 => 7,
964            nanos if (nanos / 1_000) % 10 != 0 => 6,
965            nanos if (nanos / 10_000) % 10 != 0 => 5,
966            nanos if (nanos / 100_000) % 10 != 0 => 4,
967            nanos if (nanos / 1_000_000) % 10 != 0 => 3,
968            nanos if (nanos / 10_000_000) % 10 != 0 => 2,
969            _ => 1,
970        };
971        let total_width = hour_width + subsecond_width + 7;
972
973        Metadata::new(total_width, self, TimeMetadata)
974    }
975
976    #[inline]
977    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
978        fmt::Display::fmt(self, f)
979    }
980}
981
982impl Time {
983    /// The maximum number of bytes that the `fmt_into_buffer` method will write, which is also used
984    /// for the `Display` implementation.
985    pub(crate) const DISPLAY_BUFFER_SIZE: usize = 18;
986
987    /// Format the `Time` into the provided buffer, returning the number of bytes written.
988    #[inline]
989    pub(crate) fn fmt_into_buffer(
990        self,
991        buf: &mut [MaybeUninit<u8>; Self::DISPLAY_BUFFER_SIZE],
992    ) -> usize {
993        let mut idx = 0;
994
995        // Safety: `self.hour()` is in the range required by its type.
996        let hour =
997            one_to_two_digits_no_padding(unsafe { Hours::new_unchecked(self.hour()) }.expand());
998        // Safety:
999        // - both `hour` and `buf` are valid for reads and writes of up to 2 bytes.
1000        // - `u8` is 1-aligned, so that is not a concern.
1001        // - `hour` points to static memory, while `buf` is a local variable, so they do not
1002        //   overlap.
1003        unsafe {
1004            hour.as_ptr()
1005                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), hour.len())
1006        };
1007        idx += hour.len();
1008
1009        buf[idx] = MaybeUninit::new(b':');
1010        idx += 1;
1011
1012        // Safety: See above.
1013        unsafe {
1014            two_digits_zero_padded(Minutes::new_unchecked(self.minute()).expand())
1015                .as_ptr()
1016                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2)
1017        };
1018        idx += 2;
1019
1020        buf[idx] = MaybeUninit::new(b':');
1021        idx += 1;
1022
1023        // Safety: See above.
1024        unsafe {
1025            two_digits_zero_padded(Seconds::new_unchecked(self.second()).expand())
1026                .as_ptr()
1027                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), 2)
1028        };
1029        idx += 2;
1030
1031        buf[idx] = MaybeUninit::new(b'.');
1032        idx += 1;
1033
1034        // Safety: `self.nanosecond()` is guaranteed to be less than 1,000,000,000.
1035        let subsecond = truncated_subsecond_from_nanos(unsafe {
1036            Nanoseconds::new_unchecked(self.nanosecond())
1037        });
1038        // Safety: See above, except `subsecond` is valid for 9 bytes.
1039        unsafe {
1040            subsecond
1041                .as_ptr()
1042                .copy_to_nonoverlapping(buf.as_mut_ptr().add(idx).cast(), subsecond.len())
1043        };
1044        idx += subsecond.len();
1045
1046        idx
1047    }
1048}
1049
1050impl fmt::Display for Time {
1051    #[inline]
1052    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1053        let mut buf = [MaybeUninit::uninit(); Self::DISPLAY_BUFFER_SIZE];
1054        let len = self.fmt_into_buffer(&mut buf);
1055        // Safety: All bytes up to `len` have been initialized with ASCII characters.
1056        let s = unsafe { str_from_raw_parts(buf.as_ptr().cast(), len) };
1057        f.pad(s)
1058    }
1059}
1060
1061impl fmt::Debug for Time {
1062    #[inline]
1063    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1064        fmt::Display::fmt(self, f)
1065    }
1066}
1067
1068impl Add<Duration> for Time {
1069    type Output = Self;
1070
1071    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
1072    ///
1073    /// ```rust
1074    /// # use time::ext::NumericalDuration;
1075    /// # use time_macros::time;
1076    /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
1077    /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
1078    /// ```
1079    #[inline]
1080    fn add(self, duration: Duration) -> Self::Output {
1081        self.adjusting_add(duration).1
1082    }
1083}
1084
1085impl AddAssign<Duration> for Time {
1086    #[inline]
1087    fn add_assign(&mut self, rhs: Duration) {
1088        *self = *self + rhs;
1089    }
1090}
1091
1092impl Add<StdDuration> for Time {
1093    type Output = Self;
1094
1095    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
1096    ///
1097    /// ```rust
1098    /// # use time::ext::NumericalStdDuration;
1099    /// # use time_macros::time;
1100    /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
1101    /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
1102    /// ```
1103    #[inline]
1104    fn add(self, duration: StdDuration) -> Self::Output {
1105        self.adjusting_add_std(duration).1
1106    }
1107}
1108
1109impl AddAssign<StdDuration> for Time {
1110    #[inline]
1111    fn add_assign(&mut self, rhs: StdDuration) {
1112        *self = *self + rhs;
1113    }
1114}
1115
1116impl Sub<Duration> for Time {
1117    type Output = Self;
1118
1119    /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
1120    ///
1121    /// ```rust
1122    /// # use time::ext::NumericalDuration;
1123    /// # use time_macros::time;
1124    /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
1125    /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
1126    /// ```
1127    #[inline]
1128    fn sub(self, duration: Duration) -> Self::Output {
1129        self.adjusting_sub(duration).1
1130    }
1131}
1132
1133impl SubAssign<Duration> for Time {
1134    #[inline]
1135    fn sub_assign(&mut self, rhs: Duration) {
1136        *self = *self - rhs;
1137    }
1138}
1139
1140impl Sub<StdDuration> for Time {
1141    type Output = Self;
1142
1143    /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
1144    ///
1145    /// ```rust
1146    /// # use time::ext::NumericalStdDuration;
1147    /// # use time_macros::time;
1148    /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
1149    /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
1150    /// ```
1151    #[inline]
1152    fn sub(self, duration: StdDuration) -> Self::Output {
1153        self.adjusting_sub_std(duration).1
1154    }
1155}
1156
1157impl SubAssign<StdDuration> for Time {
1158    #[inline]
1159    fn sub_assign(&mut self, rhs: StdDuration) {
1160        *self = *self - rhs;
1161    }
1162}
1163
1164impl Sub for Time {
1165    type Output = Duration;
1166
1167    /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
1168    /// the same calendar day.
1169    ///
1170    /// ```rust
1171    /// # use time::ext::NumericalDuration;
1172    /// # use time_macros::time;
1173    /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
1174    /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
1175    /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
1176    /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
1177    /// ```
1178    #[inline]
1179    fn sub(self, rhs: Self) -> Self::Output {
1180        let hour_diff = self.hour.get().cast_signed() - rhs.hour.get().cast_signed();
1181        let minute_diff = self.minute.get().cast_signed() - rhs.minute.get().cast_signed();
1182        let second_diff = self.second.get().cast_signed() - rhs.second.get().cast_signed();
1183        let nanosecond_diff =
1184            self.nanosecond.get().cast_signed() - rhs.nanosecond.get().cast_signed();
1185
1186        let seconds = hour_diff.extend::<i32>() * Second::per_t::<i32>(Hour)
1187            + minute_diff.extend::<i32>() * Second::per_t::<i32>(Minute)
1188            + second_diff.extend::<i32>();
1189
1190        let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
1191            (
1192                seconds - 1,
1193                nanosecond_diff + Nanosecond::per_t::<i32>(Second),
1194            )
1195        } else if seconds < 0 && nanosecond_diff > 0 {
1196            (
1197                seconds + 1,
1198                nanosecond_diff - Nanosecond::per_t::<i32>(Second),
1199            )
1200        } else {
1201            (seconds, nanosecond_diff)
1202        };
1203
1204        // Safety: `nanoseconds` is in range due to the overflow handling.
1205        unsafe { Duration::new_unchecked(seconds.extend(), nanoseconds) }
1206    }
1207}