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