Coverage Report

Created: 2025-02-25 06:39

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