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