Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/time-0.3.13/src/time.rs
Line
Count
Source
1
//! The [`Time`] struct and its associated `impl`s.
2
3
use core::fmt;
4
use core::ops::{Add, Sub};
5
use core::time::Duration as StdDuration;
6
#[cfg(feature = "formatting")]
7
use std::io;
8
9
#[cfg(feature = "formatting")]
10
use crate::formatting::Formattable;
11
#[cfg(feature = "parsing")]
12
use crate::parsing::Parsable;
13
use crate::util::DateAdjustment;
14
use crate::{error, Duration};
15
16
/// By explicitly inserting this enum where padding is expected, the compiler is able to better
17
/// perform niche value optimization.
18
#[repr(u8)]
19
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20
pub(crate) enum Padding {
21
    #[allow(clippy::missing_docs_in_private_items)]
22
    Optimize,
23
}
24
25
/// The clock time within a given date. Nanosecond precision.
26
///
27
/// All minutes are assumed to have exactly 60 seconds; no attempt is made to handle leap seconds
28
/// (either positive or negative).
29
///
30
/// When comparing two `Time`s, they are assumed to be in the same calendar date.
31
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
32
pub struct Time {
33
    #[allow(clippy::missing_docs_in_private_items)]
34
    hour: u8,
35
    #[allow(clippy::missing_docs_in_private_items)]
36
    minute: u8,
37
    #[allow(clippy::missing_docs_in_private_items)]
38
    second: u8,
39
    #[allow(clippy::missing_docs_in_private_items)]
40
    nanosecond: u32,
41
    #[allow(clippy::missing_docs_in_private_items)]
42
    padding: Padding,
43
}
44
45
impl fmt::Debug for Time {
46
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47
0
        f.debug_struct("Time")
48
0
            .field("hour", &self.hour)
49
0
            .field("minute", &self.minute)
50
0
            .field("second", &self.second)
51
0
            .field("nanosecond", &self.nanosecond)
52
0
            .finish()
53
0
    }
54
}
55
56
impl Time {
57
    /// Create a `Time` that is exactly midnight.
58
    ///
59
    /// ```rust
60
    /// # use time::{Time, macros::time};
61
    /// assert_eq!(Time::MIDNIGHT, time!(0:00));
62
    /// ```
63
    pub const MIDNIGHT: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0);
64
65
    /// The smallest value that can be represented by `Time`.
66
    ///
67
    /// `00:00:00.0`
68
    pub(crate) const MIN: Self = Self::__from_hms_nanos_unchecked(0, 0, 0, 0);
69
70
    /// The largest value that can be represented by `Time`.
71
    ///
72
    /// `23:59:59.999_999_999`
73
    pub(crate) const MAX: Self = Self::__from_hms_nanos_unchecked(23, 59, 59, 999_999_999);
74
75
    // region: constructors
76
    /// Create a `Time` from its components.
77
    #[doc(hidden)]
78
14.4k
    pub const fn __from_hms_nanos_unchecked(
79
14.4k
        hour: u8,
80
14.4k
        minute: u8,
81
14.4k
        second: u8,
82
14.4k
        nanosecond: u32,
83
14.4k
    ) -> Self {
84
14.4k
        debug_assert!(hour < 24);
85
14.4k
        debug_assert!(minute < 60);
86
14.4k
        debug_assert!(second < 60);
87
14.4k
        debug_assert!(nanosecond < 1_000_000_000);
88
89
14.4k
        Self {
90
14.4k
            hour,
91
14.4k
            minute,
92
14.4k
            second,
93
14.4k
            nanosecond,
94
14.4k
            padding: Padding::Optimize,
95
14.4k
        }
96
14.4k
    }
97
98
    /// Attempt to create a `Time` from the hour, minute, and second.
99
    ///
100
    /// ```rust
101
    /// # use time::Time;
102
    /// assert!(Time::from_hms(1, 2, 3).is_ok());
103
    /// ```
104
    ///
105
    /// ```rust
106
    /// # use time::Time;
107
    /// assert!(Time::from_hms(24, 0, 0).is_err()); // 24 isn't a valid hour.
108
    /// assert!(Time::from_hms(0, 60, 0).is_err()); // 60 isn't a valid minute.
109
    /// assert!(Time::from_hms(0, 0, 60).is_err()); // 60 isn't a valid second.
110
    /// ```
111
0
    pub const fn from_hms(hour: u8, minute: u8, second: u8) -> Result<Self, error::ComponentRange> {
112
0
        ensure_value_in_range!(hour in 0 => 23);
113
0
        ensure_value_in_range!(minute in 0 => 59);
114
0
        ensure_value_in_range!(second in 0 => 59);
115
0
        Ok(Self::__from_hms_nanos_unchecked(hour, minute, second, 0))
116
0
    }
117
118
    /// Attempt to create a `Time` from the hour, minute, second, and millisecond.
119
    ///
120
    /// ```rust
121
    /// # use time::Time;
122
    /// assert!(Time::from_hms_milli(1, 2, 3, 4).is_ok());
123
    /// ```
124
    ///
125
    /// ```rust
126
    /// # use time::Time;
127
    /// assert!(Time::from_hms_milli(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
128
    /// assert!(Time::from_hms_milli(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
129
    /// assert!(Time::from_hms_milli(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
130
    /// assert!(Time::from_hms_milli(0, 0, 0, 1_000).is_err()); // 1_000 isn't a valid millisecond.
131
    /// ```
132
7.12k
    pub const fn from_hms_milli(
133
7.12k
        hour: u8,
134
7.12k
        minute: u8,
135
7.12k
        second: u8,
136
7.12k
        millisecond: u16,
137
7.12k
    ) -> Result<Self, error::ComponentRange> {
138
7.12k
        ensure_value_in_range!(hour in 0 => 23);
139
7.12k
        ensure_value_in_range!(minute in 0 => 59);
140
7.12k
        ensure_value_in_range!(second in 0 => 59);
141
7.12k
        ensure_value_in_range!(millisecond in 0 => 999);
142
7.12k
        Ok(Self::__from_hms_nanos_unchecked(
143
7.12k
            hour,
144
7.12k
            minute,
145
7.12k
            second,
146
7.12k
            millisecond as u32 * 1_000_000,
147
7.12k
        ))
148
7.12k
    }
149
150
    /// Attempt to create a `Time` from the hour, minute, second, and microsecond.
151
    ///
152
    /// ```rust
153
    /// # use time::Time;
154
    /// assert!(Time::from_hms_micro(1, 2, 3, 4).is_ok());
155
    /// ```
156
    ///
157
    /// ```rust
158
    /// # use time::Time;
159
    /// assert!(Time::from_hms_micro(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
160
    /// assert!(Time::from_hms_micro(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
161
    /// assert!(Time::from_hms_micro(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
162
    /// assert!(Time::from_hms_micro(0, 0, 0, 1_000_000).is_err()); // 1_000_000 isn't a valid microsecond.
163
    /// ```
164
0
    pub const fn from_hms_micro(
165
0
        hour: u8,
166
0
        minute: u8,
167
0
        second: u8,
168
0
        microsecond: u32,
169
0
    ) -> Result<Self, error::ComponentRange> {
170
0
        ensure_value_in_range!(hour in 0 => 23);
171
0
        ensure_value_in_range!(minute in 0 => 59);
172
0
        ensure_value_in_range!(second in 0 => 59);
173
0
        ensure_value_in_range!(microsecond in 0 => 999_999);
174
0
        Ok(Self::__from_hms_nanos_unchecked(
175
0
            hour,
176
0
            minute,
177
0
            second,
178
0
            microsecond * 1_000,
179
0
        ))
180
0
    }
181
182
    /// Attempt to create a `Time` from the hour, minute, second, and nanosecond.
183
    ///
184
    /// ```rust
185
    /// # use time::Time;
186
    /// assert!(Time::from_hms_nano(1, 2, 3, 4).is_ok());
187
    /// ```
188
    ///
189
    /// ```rust
190
    /// # use time::Time;
191
    /// assert!(Time::from_hms_nano(24, 0, 0, 0).is_err()); // 24 isn't a valid hour.
192
    /// assert!(Time::from_hms_nano(0, 60, 0, 0).is_err()); // 60 isn't a valid minute.
193
    /// assert!(Time::from_hms_nano(0, 0, 60, 0).is_err()); // 60 isn't a valid second.
194
    /// assert!(Time::from_hms_nano(0, 0, 0, 1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond.
195
    /// ```
196
0
    pub const fn from_hms_nano(
197
0
        hour: u8,
198
0
        minute: u8,
199
0
        second: u8,
200
0
        nanosecond: u32,
201
0
    ) -> Result<Self, error::ComponentRange> {
202
0
        ensure_value_in_range!(hour in 0 => 23);
203
0
        ensure_value_in_range!(minute in 0 => 59);
204
0
        ensure_value_in_range!(second in 0 => 59);
205
0
        ensure_value_in_range!(nanosecond in 0 => 999_999_999);
206
0
        Ok(Self::__from_hms_nanos_unchecked(
207
0
            hour, minute, second, nanosecond,
208
0
        ))
209
0
    }
210
    // endregion constructors
211
212
    // region: getters
213
    /// Get the clock hour, minute, and second.
214
    ///
215
    /// ```rust
216
    /// # use time::macros::time;
217
    /// assert_eq!(time!(0:00:00).as_hms(), (0, 0, 0));
218
    /// assert_eq!(time!(23:59:59).as_hms(), (23, 59, 59));
219
    /// ```
220
0
    pub const fn as_hms(self) -> (u8, u8, u8) {
221
0
        (self.hour, self.minute, self.second)
222
0
    }
223
224
    /// Get the clock hour, minute, second, and millisecond.
225
    ///
226
    /// ```rust
227
    /// # use time::macros::time;
228
    /// assert_eq!(time!(0:00:00).as_hms_milli(), (0, 0, 0, 0));
229
    /// assert_eq!(time!(23:59:59.999).as_hms_milli(), (23, 59, 59, 999));
230
    /// ```
231
0
    pub const fn as_hms_milli(self) -> (u8, u8, u8, u16) {
232
0
        (
233
0
            self.hour,
234
0
            self.minute,
235
0
            self.second,
236
0
            (self.nanosecond / 1_000_000) as u16,
237
0
        )
238
0
    }
239
240
    /// Get the clock hour, minute, second, and microsecond.
241
    ///
242
    /// ```rust
243
    /// # use time::macros::time;
244
    /// assert_eq!(time!(0:00:00).as_hms_micro(), (0, 0, 0, 0));
245
    /// assert_eq!(
246
    ///     time!(23:59:59.999_999).as_hms_micro(),
247
    ///     (23, 59, 59, 999_999)
248
    /// );
249
    /// ```
250
0
    pub const fn as_hms_micro(self) -> (u8, u8, u8, u32) {
251
0
        (self.hour, self.minute, self.second, self.nanosecond / 1_000)
252
0
    }
253
254
    /// Get the clock hour, minute, second, and nanosecond.
255
    ///
256
    /// ```rust
257
    /// # use time::macros::time;
258
    /// assert_eq!(time!(0:00:00).as_hms_nano(), (0, 0, 0, 0));
259
    /// assert_eq!(
260
    ///     time!(23:59:59.999_999_999).as_hms_nano(),
261
    ///     (23, 59, 59, 999_999_999)
262
    /// );
263
    /// ```
264
0
    pub const fn as_hms_nano(self) -> (u8, u8, u8, u32) {
265
0
        (self.hour, self.minute, self.second, self.nanosecond)
266
0
    }
267
268
    /// Get the clock hour.
269
    ///
270
    /// The returned value will always be in the range `0..24`.
271
    ///
272
    /// ```rust
273
    /// # use time::macros::time;
274
    /// assert_eq!(time!(0:00:00).hour(), 0);
275
    /// assert_eq!(time!(23:59:59).hour(), 23);
276
    /// ```
277
11.5k
    pub const fn hour(self) -> u8 {
278
11.5k
        self.hour
279
11.5k
    }
280
281
    /// Get the minute within the hour.
282
    ///
283
    /// The returned value will always be in the range `0..60`.
284
    ///
285
    /// ```rust
286
    /// # use time::macros::time;
287
    /// assert_eq!(time!(0:00:00).minute(), 0);
288
    /// assert_eq!(time!(23:59:59).minute(), 59);
289
    /// ```
290
11.5k
    pub const fn minute(self) -> u8 {
291
11.5k
        self.minute
292
11.5k
    }
293
294
    /// Get the second within the minute.
295
    ///
296
    /// The returned value will always be in the range `0..60`.
297
    ///
298
    /// ```rust
299
    /// # use time::macros::time;
300
    /// assert_eq!(time!(0:00:00).second(), 0);
301
    /// assert_eq!(time!(23:59:59).second(), 59);
302
    /// ```
303
11.5k
    pub const fn second(self) -> u8 {
304
11.5k
        self.second
305
11.5k
    }
306
307
    /// Get the milliseconds within the second.
308
    ///
309
    /// The returned value will always be in the range `0..1_000`.
310
    ///
311
    /// ```rust
312
    /// # use time::macros::time;
313
    /// assert_eq!(time!(0:00).millisecond(), 0);
314
    /// assert_eq!(time!(23:59:59.999).millisecond(), 999);
315
    /// ```
316
0
    pub const fn millisecond(self) -> u16 {
317
0
        (self.nanosecond / 1_000_000) as _
318
0
    }
319
320
    /// Get the microseconds within the second.
321
    ///
322
    /// The returned value will always be in the range `0..1_000_000`.
323
    ///
324
    /// ```rust
325
    /// # use time::macros::time;
326
    /// assert_eq!(time!(0:00).microsecond(), 0);
327
    /// assert_eq!(time!(23:59:59.999_999).microsecond(), 999_999);
328
    /// ```
329
0
    pub const fn microsecond(self) -> u32 {
330
0
        self.nanosecond / 1_000
331
0
    }
332
333
    /// Get the nanoseconds within the second.
334
    ///
335
    /// The returned value will always be in the range `0..1_000_000_000`.
336
    ///
337
    /// ```rust
338
    /// # use time::macros::time;
339
    /// assert_eq!(time!(0:00).nanosecond(), 0);
340
    /// assert_eq!(time!(23:59:59.999_999_999).nanosecond(), 999_999_999);
341
    /// ```
342
0
    pub const fn nanosecond(self) -> u32 {
343
0
        self.nanosecond
344
0
    }
345
    // endregion getters
346
347
    // region: arithmetic helpers
348
    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning whether
349
    /// the date is different.
350
0
    pub(crate) const fn adjusting_add(self, duration: Duration) -> (DateAdjustment, Self) {
351
0
        let mut nanoseconds = self.nanosecond as i32 + duration.subsec_nanoseconds();
352
0
        let mut seconds = self.second as i8 + (duration.whole_seconds() % 60) as i8;
353
0
        let mut minutes = self.minute as i8 + (duration.whole_minutes() % 60) as i8;
354
0
        let mut hours = self.hour as i8 + (duration.whole_hours() % 24) as i8;
355
0
        let mut date_adjustment = DateAdjustment::None;
356
357
0
        cascade!(nanoseconds in 0..1_000_000_000 => seconds);
358
0
        cascade!(seconds in 0..60 => minutes);
359
0
        cascade!(minutes in 0..60 => hours);
360
0
        if hours >= 24 {
361
0
            hours -= 24;
362
0
            date_adjustment = DateAdjustment::Next;
363
0
        } else if hours < 0 {
364
0
            hours += 24;
365
0
            date_adjustment = DateAdjustment::Previous;
366
0
        }
367
368
0
        (
369
0
            date_adjustment,
370
0
            Self::__from_hms_nanos_unchecked(
371
0
                hours as _,
372
0
                minutes as _,
373
0
                seconds as _,
374
0
                nanoseconds as _,
375
0
            ),
376
0
        )
377
0
    }
378
379
    /// Subtract the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow, returning
380
    /// whether the date is different.
381
0
    pub(crate) const fn adjusting_sub(self, duration: Duration) -> (DateAdjustment, Self) {
382
0
        let mut nanoseconds = self.nanosecond as i32 - duration.subsec_nanoseconds();
383
0
        let mut seconds = self.second as i8 - (duration.whole_seconds() % 60) as i8;
384
0
        let mut minutes = self.minute as i8 - (duration.whole_minutes() % 60) as i8;
385
0
        let mut hours = self.hour as i8 - (duration.whole_hours() % 24) as i8;
386
0
        let mut date_adjustment = DateAdjustment::None;
387
388
0
        cascade!(nanoseconds in 0..1_000_000_000 => seconds);
389
0
        cascade!(seconds in 0..60 => minutes);
390
0
        cascade!(minutes in 0..60 => hours);
391
0
        if hours >= 24 {
392
0
            hours -= 24;
393
0
            date_adjustment = DateAdjustment::Next;
394
0
        } else if hours < 0 {
395
0
            hours += 24;
396
0
            date_adjustment = DateAdjustment::Previous;
397
0
        }
398
399
0
        (
400
0
            date_adjustment,
401
0
            Self::__from_hms_nanos_unchecked(
402
0
                hours as _,
403
0
                minutes as _,
404
0
                seconds as _,
405
0
                nanoseconds as _,
406
0
            ),
407
0
        )
408
0
    }
409
410
    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
411
    /// returning whether the date is the previous date as the first element of the tuple.
412
0
    pub(crate) const fn adjusting_add_std(self, duration: StdDuration) -> (bool, Self) {
413
0
        let mut nanosecond = self.nanosecond + duration.subsec_nanos();
414
0
        let mut second = self.second + (duration.as_secs() % 60) as u8;
415
0
        let mut minute = self.minute + ((duration.as_secs() / 60) % 60) as u8;
416
0
        let mut hour = self.hour + ((duration.as_secs() / 3_600) % 24) as u8;
417
0
        let mut is_next_day = false;
418
419
0
        cascade!(nanosecond in 0..1_000_000_000 => second);
420
0
        cascade!(second in 0..60 => minute);
421
0
        cascade!(minute in 0..60 => hour);
422
0
        if hour >= 24 {
423
0
            hour -= 24;
424
0
            is_next_day = true;
425
0
        }
426
427
0
        (
428
0
            is_next_day,
429
0
            Self::__from_hms_nanos_unchecked(hour, minute, second, nanosecond),
430
0
        )
431
0
    }
432
433
    /// Subtract the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow,
434
    /// returning whether the date is the previous date as the first element of the tuple.
435
0
    pub(crate) const fn adjusting_sub_std(self, duration: StdDuration) -> (bool, Self) {
436
0
        let mut nanosecond = self.nanosecond as i32 - duration.subsec_nanos() as i32;
437
0
        let mut second = self.second as i8 - (duration.as_secs() % 60) as i8;
438
0
        let mut minute = self.minute as i8 - ((duration.as_secs() / 60) % 60) as i8;
439
0
        let mut hour = self.hour as i8 - ((duration.as_secs() / 3_600) % 24) as i8;
440
0
        let mut is_previous_day = false;
441
442
0
        cascade!(nanosecond in 0..1_000_000_000 => second);
443
0
        cascade!(second in 0..60 => minute);
444
0
        cascade!(minute in 0..60 => hour);
445
0
        if hour < 0 {
446
0
            hour += 24;
447
0
            is_previous_day = true;
448
0
        }
449
450
0
        (
451
0
            is_previous_day,
452
0
            Self::__from_hms_nanos_unchecked(hour as _, minute as _, second as _, nanosecond as _),
453
0
        )
454
0
    }
455
    // endregion arithmetic helpers
456
457
    // region: replacement
458
    /// Replace the clock hour.
459
    ///
460
    /// ```rust
461
    /// # use time::macros::time;
462
    /// assert_eq!(
463
    ///     time!(01:02:03.004_005_006).replace_hour(7),
464
    ///     Ok(time!(07:02:03.004_005_006))
465
    /// );
466
    /// assert!(time!(01:02:03.004_005_006).replace_hour(24).is_err()); // 24 isn't a valid hour
467
    /// ```
468
    #[must_use = "This method does not mutate the original `Time`."]
469
0
    pub const fn replace_hour(self, hour: u8) -> Result<Self, error::ComponentRange> {
470
0
        ensure_value_in_range!(hour in 0 => 23);
471
0
        Ok(Self::__from_hms_nanos_unchecked(
472
0
            hour,
473
0
            self.minute,
474
0
            self.second,
475
0
            self.nanosecond,
476
0
        ))
477
0
    }
478
479
    /// Replace the minutes within the hour.
480
    ///
481
    /// ```rust
482
    /// # use time::macros::time;
483
    /// assert_eq!(
484
    ///     time!(01:02:03.004_005_006).replace_minute(7),
485
    ///     Ok(time!(01:07:03.004_005_006))
486
    /// );
487
    /// assert!(time!(01:02:03.004_005_006).replace_minute(60).is_err()); // 60 isn't a valid minute
488
    /// ```
489
    #[must_use = "This method does not mutate the original `Time`."]
490
0
    pub const fn replace_minute(self, minute: u8) -> Result<Self, error::ComponentRange> {
491
0
        ensure_value_in_range!(minute in 0 => 59);
492
0
        Ok(Self::__from_hms_nanos_unchecked(
493
0
            self.hour,
494
0
            minute,
495
0
            self.second,
496
0
            self.nanosecond,
497
0
        ))
498
0
    }
499
500
    /// Replace the seconds within the minute.
501
    ///
502
    /// ```rust
503
    /// # use time::macros::time;
504
    /// assert_eq!(
505
    ///     time!(01:02:03.004_005_006).replace_second(7),
506
    ///     Ok(time!(01:02:07.004_005_006))
507
    /// );
508
    /// assert!(time!(01:02:03.004_005_006).replace_second(60).is_err()); // 60 isn't a valid second
509
    /// ```
510
    #[must_use = "This method does not mutate the original `Time`."]
511
0
    pub const fn replace_second(self, second: u8) -> Result<Self, error::ComponentRange> {
512
0
        ensure_value_in_range!(second in 0 => 59);
513
0
        Ok(Self::__from_hms_nanos_unchecked(
514
0
            self.hour,
515
0
            self.minute,
516
0
            second,
517
0
            self.nanosecond,
518
0
        ))
519
0
    }
520
521
    /// Replace the milliseconds within the second.
522
    ///
523
    /// ```rust
524
    /// # use time::macros::time;
525
    /// assert_eq!(
526
    ///     time!(01:02:03.004_005_006).replace_millisecond(7),
527
    ///     Ok(time!(01:02:03.007))
528
    /// );
529
    /// assert!(time!(01:02:03.004_005_006).replace_millisecond(1_000).is_err()); // 1_000 isn't a valid millisecond
530
    /// ```
531
    #[must_use = "This method does not mutate the original `Time`."]
532
0
    pub const fn replace_millisecond(
533
0
        self,
534
0
        millisecond: u16,
535
0
    ) -> Result<Self, error::ComponentRange> {
536
0
        ensure_value_in_range!(millisecond in 0 => 999);
537
0
        Ok(Self::__from_hms_nanos_unchecked(
538
0
            self.hour,
539
0
            self.minute,
540
0
            self.second,
541
0
            millisecond as u32 * 1_000_000,
542
0
        ))
543
0
    }
544
545
    /// Replace the microseconds within the second.
546
    ///
547
    /// ```rust
548
    /// # use time::macros::time;
549
    /// assert_eq!(
550
    ///     time!(01:02:03.004_005_006).replace_microsecond(7_008),
551
    ///     Ok(time!(01:02:03.007_008))
552
    /// );
553
    /// assert!(time!(01:02:03.004_005_006).replace_microsecond(1_000_000).is_err()); // 1_000_000 isn't a valid microsecond
554
    /// ```
555
    #[must_use = "This method does not mutate the original `Time`."]
556
0
    pub const fn replace_microsecond(
557
0
        self,
558
0
        microsecond: u32,
559
0
    ) -> Result<Self, error::ComponentRange> {
560
0
        ensure_value_in_range!(microsecond in 0 => 999_999);
561
0
        Ok(Self::__from_hms_nanos_unchecked(
562
0
            self.hour,
563
0
            self.minute,
564
0
            self.second,
565
0
            microsecond * 1000,
566
0
        ))
567
0
    }
568
569
    /// Replace the nanoseconds within the second.
570
    ///
571
    /// ```rust
572
    /// # use time::macros::time;
573
    /// assert_eq!(
574
    ///     time!(01:02:03.004_005_006).replace_nanosecond(7_008_009),
575
    ///     Ok(time!(01:02:03.007_008_009))
576
    /// );
577
    /// assert!(time!(01:02:03.004_005_006).replace_nanosecond(1_000_000_000).is_err()); // 1_000_000_000 isn't a valid nanosecond
578
    /// ```
579
    #[must_use = "This method does not mutate the original `Time`."]
580
0
    pub const fn replace_nanosecond(self, nanosecond: u32) -> Result<Self, error::ComponentRange> {
581
0
        ensure_value_in_range!(nanosecond in 0 => 999_999_999);
582
0
        Ok(Self::__from_hms_nanos_unchecked(
583
0
            self.hour,
584
0
            self.minute,
585
0
            self.second,
586
0
            nanosecond,
587
0
        ))
588
0
    }
589
    // endregion replacement
590
}
591
592
// region: formatting & parsing
593
#[cfg(feature = "formatting")]
594
impl Time {
595
    /// Format the `Time` using the provided [format description](crate::format_description).
596
0
    pub fn format_into(
597
0
        self,
598
0
        output: &mut impl io::Write,
599
0
        format: &(impl Formattable + ?Sized),
600
0
    ) -> Result<usize, crate::error::Format> {
601
0
        format.format_into(output, None, Some(self), None)
602
0
    }
603
604
    /// Format the `Time` using the provided [format description](crate::format_description).
605
    ///
606
    /// ```rust
607
    /// # use time::{format_description, macros::time};
608
    /// let format = format_description::parse("[hour]:[minute]:[second]")?;
609
    /// assert_eq!(time!(12:00).format(&format)?, "12:00:00");
610
    /// # Ok::<_, time::Error>(())
611
    /// ```
612
0
    pub fn format(
613
0
        self,
614
0
        format: &(impl Formattable + ?Sized),
615
0
    ) -> Result<String, crate::error::Format> {
616
0
        format.format(None, Some(self), None)
617
0
    }
618
}
619
620
#[cfg(feature = "parsing")]
621
impl Time {
622
    /// Parse a `Time` from the input using the provided [format
623
    /// description](crate::format_description).
624
    ///
625
    /// ```rust
626
    /// # use time::{format_description, macros::time, Time};
627
    /// let format = format_description::parse("[hour]:[minute]:[second]")?;
628
    /// assert_eq!(Time::parse("12:00:00", &format)?, time!(12:00));
629
    /// # Ok::<_, time::Error>(())
630
    /// ```
631
0
    pub fn parse(
632
0
        input: &str,
633
0
        description: &(impl Parsable + ?Sized),
634
0
    ) -> Result<Self, error::Parse> {
635
0
        description.parse_time(input.as_bytes())
636
0
    }
637
}
638
639
impl fmt::Display for Time {
640
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
641
0
        let (value, width) = match self.nanosecond() {
642
0
            nanos if nanos % 10 != 0 => (nanos, 9),
643
0
            nanos if (nanos / 10) % 10 != 0 => (nanos / 10, 8),
644
0
            nanos if (nanos / 100) % 10 != 0 => (nanos / 100, 7),
645
0
            nanos if (nanos / 1_000) % 10 != 0 => (nanos / 1_000, 6),
646
0
            nanos if (nanos / 10_000) % 10 != 0 => (nanos / 10_000, 5),
647
0
            nanos if (nanos / 100_000) % 10 != 0 => (nanos / 100_000, 4),
648
0
            nanos if (nanos / 1_000_000) % 10 != 0 => (nanos / 1_000_000, 3),
649
0
            nanos if (nanos / 10_000_000) % 10 != 0 => (nanos / 10_000_000, 2),
650
0
            nanos => (nanos / 100_000_000, 1),
651
        };
652
0
        write!(
653
0
            f,
654
0
            "{}:{:02}:{:02}.{:0width$}",
655
            self.hour,
656
            self.minute,
657
            self.second,
658
            value,
659
            width = width
660
        )
661
0
    }
662
}
663
// endregion formatting & parsing
664
665
// region: trait impls
666
impl Add<Duration> for Time {
667
    type Output = Self;
668
669
    /// Add the sub-day time of the [`Duration`] to the `Time`. Wraps on overflow.
670
    ///
671
    /// ```rust
672
    /// # use time::{ext::NumericalDuration, macros::time};
673
    /// assert_eq!(time!(12:00) + 2.hours(), time!(14:00));
674
    /// assert_eq!(time!(0:00:01) + (-2).seconds(), time!(23:59:59));
675
    /// ```
676
0
    fn add(self, duration: Duration) -> Self::Output {
677
0
        self.adjusting_add(duration).1
678
0
    }
679
}
680
681
impl Add<StdDuration> for Time {
682
    type Output = Self;
683
684
    /// Add the sub-day time of the [`std::time::Duration`] to the `Time`. Wraps on overflow.
685
    ///
686
    /// ```rust
687
    /// # use time::{ext::NumericalStdDuration, macros::time};
688
    /// assert_eq!(time!(12:00) + 2.std_hours(), time!(14:00));
689
    /// assert_eq!(time!(23:59:59) + 2.std_seconds(), time!(0:00:01));
690
    /// ```
691
0
    fn add(self, duration: StdDuration) -> Self::Output {
692
0
        self.adjusting_add_std(duration).1
693
0
    }
694
}
695
696
impl_add_assign!(Time: Duration, StdDuration);
697
698
impl Sub<Duration> for Time {
699
    type Output = Self;
700
701
    /// Subtract the sub-day time of the [`Duration`] from the `Time`. Wraps on overflow.
702
    ///
703
    /// ```rust
704
    /// # use time::{ext::NumericalDuration, macros::time};
705
    /// assert_eq!(time!(14:00) - 2.hours(), time!(12:00));
706
    /// assert_eq!(time!(23:59:59) - (-2).seconds(), time!(0:00:01));
707
    /// ```
708
0
    fn sub(self, duration: Duration) -> Self::Output {
709
0
        self.adjusting_sub(duration).1
710
0
    }
711
}
712
713
impl Sub<StdDuration> for Time {
714
    type Output = Self;
715
716
    /// Subtract the sub-day time of the [`std::time::Duration`] from the `Time`. Wraps on overflow.
717
    ///
718
    /// ```rust
719
    /// # use time::{ext::NumericalStdDuration, macros::time};
720
    /// assert_eq!(time!(14:00) - 2.std_hours(), time!(12:00));
721
    /// assert_eq!(time!(0:00:01) - 2.std_seconds(), time!(23:59:59));
722
    /// ```
723
0
    fn sub(self, duration: StdDuration) -> Self::Output {
724
0
        self.adjusting_sub_std(duration).1
725
0
    }
726
}
727
728
impl_sub_assign!(Time: Duration, StdDuration);
729
730
impl Sub for Time {
731
    type Output = Duration;
732
733
    /// Subtract two `Time`s, returning the [`Duration`] between. This assumes both `Time`s are in
734
    /// the same calendar day.
735
    ///
736
    /// ```rust
737
    /// # use time::{ext::NumericalDuration, macros::time};
738
    /// assert_eq!(time!(0:00) - time!(0:00), 0.seconds());
739
    /// assert_eq!(time!(1:00) - time!(0:00), 1.hours());
740
    /// assert_eq!(time!(0:00) - time!(1:00), (-1).hours());
741
    /// assert_eq!(time!(0:00) - time!(23:00), (-23).hours());
742
    /// ```
743
0
    fn sub(self, rhs: Self) -> Self::Output {
744
0
        let hour_diff = (self.hour as i8) - (rhs.hour as i8);
745
0
        let minute_diff = (self.minute as i8) - (rhs.minute as i8);
746
0
        let second_diff = (self.second as i8) - (rhs.second as i8);
747
0
        let nanosecond_diff = (self.nanosecond as i32) - (rhs.nanosecond as i32);
748
749
0
        let seconds = hour_diff as i64 * 3_600 + minute_diff as i64 * 60 + second_diff as i64;
750
751
0
        let (seconds, nanoseconds) = if seconds > 0 && nanosecond_diff < 0 {
752
0
            (seconds - 1, nanosecond_diff + 1_000_000_000)
753
0
        } else if seconds < 0 && nanosecond_diff > 0 {
754
0
            (seconds + 1, nanosecond_diff - 1_000_000_000)
755
        } else {
756
0
            (seconds, nanosecond_diff)
757
        };
758
759
0
        Duration::new_unchecked(seconds, nanoseconds)
760
0
    }
761
}
762
// endregion trait impls