Coverage Report

Created: 2025-11-16 06:35

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