Coverage Report

Created: 2025-07-23 07:29

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