Coverage Report

Created: 2024-12-17 06:15

/rust/registry/src/index.crates.io-6f17d22bba15001f/time-0.3.37/src/duration.rs
Line
Count
Source (jump to first uncovered line)
1
//! The [`Duration`] struct and its associated `impl`s.
2
3
use core::cmp::Ordering;
4
use core::fmt;
5
use core::iter::Sum;
6
use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
7
use core::time::Duration as StdDuration;
8
9
use deranged::RangedI32;
10
use num_conv::prelude::*;
11
12
use crate::convert::*;
13
use crate::error;
14
use crate::internal_macros::{
15
    const_try_opt, expect_opt, impl_add_assign, impl_div_assign, impl_mul_assign, impl_sub_assign,
16
};
17
#[cfg(feature = "std")]
18
#[allow(deprecated)]
19
use crate::Instant;
20
21
/// By explicitly inserting this enum where padding is expected, the compiler is able to better
22
/// perform niche value optimization.
23
#[repr(u32)]
24
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
25
pub(crate) enum Padding {
26
    #[allow(clippy::missing_docs_in_private_items)]
27
    Optimize,
28
}
29
30
/// The type of the `nanosecond` field of `Duration`.
31
type Nanoseconds =
32
    RangedI32<{ -(Nanosecond::per(Second) as i32 - 1) }, { Nanosecond::per(Second) as i32 - 1 }>;
33
34
/// A span of time with nanosecond precision.
35
///
36
/// Each `Duration` is composed of a whole number of seconds and a fractional part represented in
37
/// nanoseconds.
38
///
39
/// This implementation allows for negative durations, unlike [`core::time::Duration`].
40
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
41
pub struct Duration {
42
    /// Number of whole seconds.
43
    seconds: i64,
44
    /// Number of nanoseconds within the second. The sign always matches the `seconds` field.
45
    // Sign must match that of `seconds` (though this is not a safety requirement).
46
    nanoseconds: Nanoseconds,
47
    #[allow(clippy::missing_docs_in_private_items)]
48
    padding: Padding,
49
}
50
51
impl fmt::Debug for Duration {
52
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53
0
        f.debug_struct("Duration")
54
0
            .field("seconds", &self.seconds)
55
0
            .field("nanoseconds", &self.nanoseconds)
56
0
            .finish()
57
0
    }
58
}
59
60
impl Default for Duration {
61
0
    fn default() -> Self {
62
0
        Self {
63
0
            seconds: 0,
64
0
            nanoseconds: Nanoseconds::new_static::<0>(),
65
0
            padding: Padding::Optimize,
66
0
        }
67
0
    }
68
}
69
70
/// This is adapted from the [`std` implementation][std], which uses mostly bit
71
/// operations to ensure the highest precision:
72
///
73
/// Changes from `std` are marked and explained below.
74
///
75
/// [std]: https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340
76
#[rustfmt::skip] // Skip `rustfmt` because it reformats the arguments of the macro weirdly.
77
macro_rules! try_from_secs {
78
    (
79
        secs = $secs: expr,
80
        mantissa_bits = $mant_bits: literal,
81
        exponent_bits = $exp_bits: literal,
82
        offset = $offset: literal,
83
        bits_ty = $bits_ty:ty,
84
        bits_ty_signed = $bits_ty_signed:ty,
85
        double_ty = $double_ty:ty,
86
        float_ty = $float_ty:ty,
87
        is_nan = $is_nan:expr,
88
        is_overflow = $is_overflow:expr,
89
    ) => {{
90
        'value: {
91
            const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2;
92
            const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1;
93
            const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1;
94
95
            // Change from std: No error check for negative values necessary.
96
97
            let bits = $secs.to_bits();
98
            let mant = (bits & MANT_MASK) | (MANT_MASK + 1);
99
            let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP;
100
101
            let (secs, nanos) = if exp < -31 {
102
                // the input represents less than 1ns and can not be rounded to it
103
                (0u64, 0u32)
104
            } else if exp < 0 {
105
                // the input is less than 1 second
106
                let t = <$double_ty>::from(mant) << ($offset + exp);
107
                let nanos_offset = $mant_bits + $offset;
108
                let nanos_tmp = u128::from(Nanosecond::per(Second)) * u128::from(t);
109
                let nanos = (nanos_tmp >> nanos_offset) as u32;
110
111
                let rem_mask = (1 << nanos_offset) - 1;
112
                let rem_msb_mask = 1 << (nanos_offset - 1);
113
                let rem = nanos_tmp & rem_mask;
114
                let is_tie = rem == rem_msb_mask;
115
                let is_even = (nanos & 1) == 0;
116
                let rem_msb = nanos_tmp & rem_msb_mask == 0;
117
                let add_ns = !(rem_msb || (is_even && is_tie));
118
119
                // f32 does not have enough precision to trigger the second branch
120
                // since it can not represent numbers between 0.999_999_940_395 and 1.0.
121
                let nanos = nanos + add_ns as u32;
122
                if ($mant_bits == 23) || (nanos != Nanosecond::per(Second)) {
123
                    (0, nanos)
124
                } else {
125
                    (1, 0)
126
                }
127
            } else if exp < $mant_bits {
128
                let secs = u64::from(mant >> ($mant_bits - exp));
129
                let t = <$double_ty>::from((mant << exp) & MANT_MASK);
130
                let nanos_offset = $mant_bits;
131
                let nanos_tmp = <$double_ty>::from(Nanosecond::per(Second)) * t;
132
                let nanos = (nanos_tmp >> nanos_offset) as u32;
133
134
                let rem_mask = (1 << nanos_offset) - 1;
135
                let rem_msb_mask = 1 << (nanos_offset - 1);
136
                let rem = nanos_tmp & rem_mask;
137
                let is_tie = rem == rem_msb_mask;
138
                let is_even = (nanos & 1) == 0;
139
                let rem_msb = nanos_tmp & rem_msb_mask == 0;
140
                let add_ns = !(rem_msb || (is_even && is_tie));
141
142
                // f32 does not have enough precision to trigger the second branch.
143
                // For example, it can not represent numbers between 1.999_999_880...
144
                // and 2.0. Bigger values result in even smaller precision of the
145
                // fractional part.
146
                let nanos = nanos + add_ns as u32;
147
                if ($mant_bits == 23) || (nanos != Nanosecond::per(Second)) {
148
                    (secs, nanos)
149
                } else {
150
                    (secs + 1, 0)
151
                }
152
            } else if exp < 63 {
153
                // Change from std: The exponent here is 63 instead of 64,
154
                // because i64::MAX + 1 is 2^63.
155
156
                // the input has no fractional part
157
                let secs = u64::from(mant) << (exp - $mant_bits);
158
                (secs, 0)
159
            } else if bits == (i64::MIN as $float_ty).to_bits() {
160
                // Change from std: Signed integers are asymmetrical in that
161
                // iN::MIN is -iN::MAX - 1. So for example i8 covers the
162
                // following numbers -128..=127. The check above (exp < 63)
163
                // doesn't cover i64::MIN as that is -2^63, so we have this
164
                // additional case to handle the asymmetry of iN::MIN.
165
                break 'value Self::new_ranged_unchecked(i64::MIN, Nanoseconds::new_static::<0>());
166
            } else if $secs.is_nan() {
167
                // Change from std: std doesn't differentiate between the error
168
                // cases.
169
                $is_nan
170
            } else {
171
                $is_overflow
172
            };
173
174
            // Change from std: All the code is mostly unmodified in that it
175
            // simply calculates an unsigned integer. Here we extract the sign
176
            // bit and assign it to the number. We basically manually do two's
177
            // complement here, we could also use an if and just negate the
178
            // numbers based on the sign, but it turns out to be quite a bit
179
            // slower.
180
            let mask = (bits as $bits_ty_signed) >> ($mant_bits + $exp_bits);
181
            #[allow(trivial_numeric_casts)]
182
            let secs_signed = ((secs as i64) ^ (mask as i64)) - (mask as i64);
183
            #[allow(trivial_numeric_casts)]
184
            let nanos_signed = ((nanos as i32) ^ (mask as i32)) - (mask as i32);
185
            // Safety: `nanos_signed` is in range.
186
            unsafe { Self::new_unchecked(secs_signed, nanos_signed) }
187
        }
188
    }};
189
}
190
191
impl Duration {
192
    // region: constants
193
    /// Equivalent to `0.seconds()`.
194
    ///
195
    /// ```rust
196
    /// # use time::{Duration, ext::NumericalDuration};
197
    /// assert_eq!(Duration::ZERO, 0.seconds());
198
    /// ```
199
    pub const ZERO: Self = Self::seconds(0);
200
201
    /// Equivalent to `1.nanoseconds()`.
202
    ///
203
    /// ```rust
204
    /// # use time::{Duration, ext::NumericalDuration};
205
    /// assert_eq!(Duration::NANOSECOND, 1.nanoseconds());
206
    /// ```
207
    pub const NANOSECOND: Self = Self::nanoseconds(1);
208
209
    /// Equivalent to `1.microseconds()`.
210
    ///
211
    /// ```rust
212
    /// # use time::{Duration, ext::NumericalDuration};
213
    /// assert_eq!(Duration::MICROSECOND, 1.microseconds());
214
    /// ```
215
    pub const MICROSECOND: Self = Self::microseconds(1);
216
217
    /// Equivalent to `1.milliseconds()`.
218
    ///
219
    /// ```rust
220
    /// # use time::{Duration, ext::NumericalDuration};
221
    /// assert_eq!(Duration::MILLISECOND, 1.milliseconds());
222
    /// ```
223
    pub const MILLISECOND: Self = Self::milliseconds(1);
224
225
    /// Equivalent to `1.seconds()`.
226
    ///
227
    /// ```rust
228
    /// # use time::{Duration, ext::NumericalDuration};
229
    /// assert_eq!(Duration::SECOND, 1.seconds());
230
    /// ```
231
    pub const SECOND: Self = Self::seconds(1);
232
233
    /// Equivalent to `1.minutes()`.
234
    ///
235
    /// ```rust
236
    /// # use time::{Duration, ext::NumericalDuration};
237
    /// assert_eq!(Duration::MINUTE, 1.minutes());
238
    /// ```
239
    pub const MINUTE: Self = Self::minutes(1);
240
241
    /// Equivalent to `1.hours()`.
242
    ///
243
    /// ```rust
244
    /// # use time::{Duration, ext::NumericalDuration};
245
    /// assert_eq!(Duration::HOUR, 1.hours());
246
    /// ```
247
    pub const HOUR: Self = Self::hours(1);
248
249
    /// Equivalent to `1.days()`.
250
    ///
251
    /// ```rust
252
    /// # use time::{Duration, ext::NumericalDuration};
253
    /// assert_eq!(Duration::DAY, 1.days());
254
    /// ```
255
    pub const DAY: Self = Self::days(1);
256
257
    /// Equivalent to `1.weeks()`.
258
    ///
259
    /// ```rust
260
    /// # use time::{Duration, ext::NumericalDuration};
261
    /// assert_eq!(Duration::WEEK, 1.weeks());
262
    /// ```
263
    pub const WEEK: Self = Self::weeks(1);
264
265
    /// The minimum possible duration. Adding any negative duration to this will cause an overflow.
266
    pub const MIN: Self = Self::new_ranged(i64::MIN, Nanoseconds::MIN);
267
268
    /// The maximum possible duration. Adding any positive duration to this will cause an overflow.
269
    pub const MAX: Self = Self::new_ranged(i64::MAX, Nanoseconds::MAX);
270
    // endregion constants
271
272
    // region: is_{sign}
273
    /// Check if a duration is exactly zero.
274
    ///
275
    /// ```rust
276
    /// # use time::ext::NumericalDuration;
277
    /// assert!(0.seconds().is_zero());
278
    /// assert!(!1.nanoseconds().is_zero());
279
    /// ```
280
0
    pub const fn is_zero(self) -> bool {
281
0
        self.seconds == 0 && self.nanoseconds.get() == 0
282
0
    }
283
284
    /// Check if a duration is negative.
285
    ///
286
    /// ```rust
287
    /// # use time::ext::NumericalDuration;
288
    /// assert!((-1).seconds().is_negative());
289
    /// assert!(!0.seconds().is_negative());
290
    /// assert!(!1.seconds().is_negative());
291
    /// ```
292
0
    pub const fn is_negative(self) -> bool {
293
0
        self.seconds < 0 || self.nanoseconds.get() < 0
294
0
    }
295
296
    /// Check if a duration is positive.
297
    ///
298
    /// ```rust
299
    /// # use time::ext::NumericalDuration;
300
    /// assert!(1.seconds().is_positive());
301
    /// assert!(!0.seconds().is_positive());
302
    /// assert!(!(-1).seconds().is_positive());
303
    /// ```
304
0
    pub const fn is_positive(self) -> bool {
305
0
        self.seconds > 0 || self.nanoseconds.get() > 0
306
0
    }
307
    // endregion is_{sign}
308
309
    // region: abs
310
    /// Get the absolute value of the duration.
311
    ///
312
    /// This method saturates the returned value if it would otherwise overflow.
313
    ///
314
    /// ```rust
315
    /// # use time::ext::NumericalDuration;
316
    /// assert_eq!(1.seconds().abs(), 1.seconds());
317
    /// assert_eq!(0.seconds().abs(), 0.seconds());
318
    /// assert_eq!((-1).seconds().abs(), 1.seconds());
319
    /// ```
320
0
    pub const fn abs(self) -> Self {
321
0
        match self.seconds.checked_abs() {
322
0
            Some(seconds) => Self::new_ranged_unchecked(seconds, self.nanoseconds.abs()),
323
0
            None => Self::MAX,
324
        }
325
0
    }
326
327
    /// Convert the existing `Duration` to a `std::time::Duration` and its sign. This returns a
328
    /// [`std::time::Duration`] and does not saturate the returned value (unlike [`Duration::abs`]).
329
    ///
330
    /// ```rust
331
    /// # use time::ext::{NumericalDuration, NumericalStdDuration};
332
    /// assert_eq!(1.seconds().unsigned_abs(), 1.std_seconds());
333
    /// assert_eq!(0.seconds().unsigned_abs(), 0.std_seconds());
334
    /// assert_eq!((-1).seconds().unsigned_abs(), 1.std_seconds());
335
    /// ```
336
0
    pub const fn unsigned_abs(self) -> StdDuration {
337
0
        StdDuration::new(
338
0
            self.seconds.unsigned_abs(),
339
0
            self.nanoseconds.get().unsigned_abs(),
340
0
        )
341
0
    }
342
    // endregion abs
343
344
    // region: constructors
345
    /// Create a new `Duration` without checking the validity of the components.
346
    ///
347
    /// # Safety
348
    ///
349
    /// - `nanoseconds` must be in the range `-999_999_999..=999_999_999`.
350
    ///
351
    /// While the sign of `nanoseconds` is required to be the same as the sign of `seconds`, this is
352
    /// not a safety invariant.
353
0
    pub(crate) const unsafe fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
354
0
        Self::new_ranged_unchecked(
355
0
            seconds,
356
0
            // Safety: The caller must uphold the safety invariants.
357
0
            unsafe { Nanoseconds::new_unchecked(nanoseconds) },
358
0
        )
359
0
    }
360
361
    /// Create a new `Duration` without checking the validity of the components.
362
0
    pub(crate) const fn new_ranged_unchecked(seconds: i64, nanoseconds: Nanoseconds) -> Self {
363
0
        if seconds < 0 {
364
0
            debug_assert!(nanoseconds.get() <= 0);
365
0
        } else if seconds > 0 {
366
0
            debug_assert!(nanoseconds.get() >= 0);
367
0
        }
368
369
0
        Self {
370
0
            seconds,
371
0
            nanoseconds,
372
0
            padding: Padding::Optimize,
373
0
        }
374
0
    }
375
376
    /// Create a new `Duration` with the provided seconds and nanoseconds. If nanoseconds is at
377
    /// least ±10<sup>9</sup>, it will wrap to the number of seconds.
378
    ///
379
    /// ```rust
380
    /// # use time::{Duration, ext::NumericalDuration};
381
    /// assert_eq!(Duration::new(1, 0), 1.seconds());
382
    /// assert_eq!(Duration::new(-1, 0), (-1).seconds());
383
    /// assert_eq!(Duration::new(1, 2_000_000_000), 3.seconds());
384
    /// ```
385
    ///
386
    /// # Panics
387
    ///
388
    /// This may panic if an overflow occurs.
389
0
    pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self {
390
0
        seconds = expect_opt!(
391
0
            seconds.checked_add(nanoseconds as i64 / Nanosecond::per(Second) as i64),
392
0
            "overflow constructing `time::Duration`"
393
        );
394
0
        nanoseconds %= Nanosecond::per(Second) as i32;
395
0
396
0
        if seconds > 0 && nanoseconds < 0 {
397
0
            // `seconds` cannot overflow here because it is positive.
398
0
            seconds -= 1;
399
0
            nanoseconds += Nanosecond::per(Second) as i32;
400
0
        } else if seconds < 0 && nanoseconds > 0 {
401
0
            // `seconds` cannot overflow here because it is negative.
402
0
            seconds += 1;
403
0
            nanoseconds -= Nanosecond::per(Second) as i32;
404
0
        }
405
406
        // Safety: `nanoseconds` is in range due to the modulus above.
407
0
        unsafe { Self::new_unchecked(seconds, nanoseconds) }
408
0
    }
409
410
    /// Create a new `Duration` with the provided seconds and nanoseconds.
411
0
    pub(crate) const fn new_ranged(mut seconds: i64, mut nanoseconds: Nanoseconds) -> Self {
412
0
        if seconds > 0 && nanoseconds.get() < 0 {
413
0
            // `seconds` cannot overflow here because it is positive.
414
0
            seconds -= 1;
415
0
            // Safety: `nanoseconds` is negative with a maximum of 999,999,999, so adding a billion
416
0
            // to it is guaranteed to result in an in-range value.
417
0
            nanoseconds = unsafe {
418
0
                Nanoseconds::new_unchecked(nanoseconds.get() + Nanosecond::per(Second) as i32)
419
0
            };
420
0
        } else if seconds < 0 && nanoseconds.get() > 0 {
421
0
            // `seconds` cannot overflow here because it is negative.
422
0
            seconds += 1;
423
0
            // Safety: `nanoseconds` is positive with a minimum of -999,999,999, so subtracting a
424
0
            // billion from it is guaranteed to result in an in-range value.
425
0
            nanoseconds = unsafe {
426
0
                Nanoseconds::new_unchecked(nanoseconds.get() - Nanosecond::per(Second) as i32)
427
0
            };
428
0
        }
429
430
0
        Self::new_ranged_unchecked(seconds, nanoseconds)
431
0
    }
432
433
    /// Create a new `Duration` with the given number of weeks. Equivalent to
434
    /// `Duration::seconds(weeks * 604_800)`.
435
    ///
436
    /// ```rust
437
    /// # use time::{Duration, ext::NumericalDuration};
438
    /// assert_eq!(Duration::weeks(1), 604_800.seconds());
439
    /// ```
440
    ///
441
    /// # Panics
442
    ///
443
    /// This may panic if an overflow occurs.
444
0
    pub const fn weeks(weeks: i64) -> Self {
445
0
        Self::seconds(expect_opt!(
446
0
            weeks.checked_mul(Second::per(Week) as _),
447
0
            "overflow constructing `time::Duration`"
448
        ))
449
0
    }
450
451
    /// Create a new `Duration` with the given number of days. Equivalent to
452
    /// `Duration::seconds(days * 86_400)`.
453
    ///
454
    /// ```rust
455
    /// # use time::{Duration, ext::NumericalDuration};
456
    /// assert_eq!(Duration::days(1), 86_400.seconds());
457
    /// ```
458
    ///
459
    /// # Panics
460
    ///
461
    /// This may panic if an overflow occurs.
462
0
    pub const fn days(days: i64) -> Self {
463
0
        Self::seconds(expect_opt!(
464
0
            days.checked_mul(Second::per(Day) as _),
465
0
            "overflow constructing `time::Duration`"
466
        ))
467
0
    }
468
469
    /// Create a new `Duration` with the given number of hours. Equivalent to
470
    /// `Duration::seconds(hours * 3_600)`.
471
    ///
472
    /// ```rust
473
    /// # use time::{Duration, ext::NumericalDuration};
474
    /// assert_eq!(Duration::hours(1), 3_600.seconds());
475
    /// ```
476
    ///
477
    /// # Panics
478
    ///
479
    /// This may panic if an overflow occurs.
480
0
    pub const fn hours(hours: i64) -> Self {
481
0
        Self::seconds(expect_opt!(
482
0
            hours.checked_mul(Second::per(Hour) as _),
483
0
            "overflow constructing `time::Duration`"
484
        ))
485
0
    }
486
487
    /// Create a new `Duration` with the given number of minutes. Equivalent to
488
    /// `Duration::seconds(minutes * 60)`.
489
    ///
490
    /// ```rust
491
    /// # use time::{Duration, ext::NumericalDuration};
492
    /// assert_eq!(Duration::minutes(1), 60.seconds());
493
    /// ```
494
    ///
495
    /// # Panics
496
    ///
497
    /// This may panic if an overflow occurs.
498
0
    pub const fn minutes(minutes: i64) -> Self {
499
0
        Self::seconds(expect_opt!(
500
0
            minutes.checked_mul(Second::per(Minute) as _),
501
0
            "overflow constructing `time::Duration`"
502
        ))
503
0
    }
504
505
    /// Create a new `Duration` with the given number of seconds.
506
    ///
507
    /// ```rust
508
    /// # use time::{Duration, ext::NumericalDuration};
509
    /// assert_eq!(Duration::seconds(1), 1_000.milliseconds());
510
    /// ```
511
0
    pub const fn seconds(seconds: i64) -> Self {
512
0
        Self::new_ranged_unchecked(seconds, Nanoseconds::new_static::<0>())
513
0
    }
514
515
    /// Creates a new `Duration` from the specified number of seconds represented as `f64`.
516
    ///
517
    /// ```rust
518
    /// # use time::{Duration, ext::NumericalDuration};
519
    /// assert_eq!(Duration::seconds_f64(0.5), 0.5.seconds());
520
    /// assert_eq!(Duration::seconds_f64(-0.5), (-0.5).seconds());
521
    /// ```
522
0
    pub fn seconds_f64(seconds: f64) -> Self {
523
0
        try_from_secs!(
524
0
            secs = seconds,
525
0
            mantissa_bits = 52,
526
            exponent_bits = 11,
527
            offset = 44,
528
            bits_ty = u64,
529
            bits_ty_signed = i64,
530
            double_ty = u128,
531
            float_ty = f64,
532
0
            is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f64`"),
533
0
            is_overflow = crate::expect_failed("overflow constructing `time::Duration`"),
534
        )
535
0
    }
536
537
    /// Creates a new `Duration` from the specified number of seconds represented as `f32`.
538
    ///
539
    /// ```rust
540
    /// # use time::{Duration, ext::NumericalDuration};
541
    /// assert_eq!(Duration::seconds_f32(0.5), 0.5.seconds());
542
    /// assert_eq!(Duration::seconds_f32(-0.5), (-0.5).seconds());
543
    /// ```
544
0
    pub fn seconds_f32(seconds: f32) -> Self {
545
0
        try_from_secs!(
546
0
            secs = seconds,
547
0
            mantissa_bits = 23,
548
            exponent_bits = 8,
549
            offset = 41,
550
            bits_ty = u32,
551
            bits_ty_signed = i32,
552
            double_ty = u64,
553
            float_ty = f32,
554
0
            is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f32`"),
555
0
            is_overflow = crate::expect_failed("overflow constructing `time::Duration`"),
556
        )
557
0
    }
558
559
    /// Creates a new `Duration` from the specified number of seconds
560
    /// represented as `f64`. Any values that are out of bounds are saturated at
561
    /// the minimum or maximum respectively. `NaN` gets turned into a `Duration`
562
    /// of 0 seconds.
563
    ///
564
    /// ```rust
565
    /// # use time::{Duration, ext::NumericalDuration};
566
    /// assert_eq!(Duration::saturating_seconds_f64(0.5), 0.5.seconds());
567
    /// assert_eq!(Duration::saturating_seconds_f64(-0.5), (-0.5).seconds());
568
    /// assert_eq!(
569
    ///     Duration::saturating_seconds_f64(f64::NAN),
570
    ///     Duration::new(0, 0),
571
    /// );
572
    /// assert_eq!(
573
    ///     Duration::saturating_seconds_f64(f64::NEG_INFINITY),
574
    ///     Duration::MIN,
575
    /// );
576
    /// assert_eq!(
577
    ///     Duration::saturating_seconds_f64(f64::INFINITY),
578
    ///     Duration::MAX,
579
    /// );
580
    /// ```
581
0
    pub fn saturating_seconds_f64(seconds: f64) -> Self {
582
0
        try_from_secs!(
583
0
            secs = seconds,
584
0
            mantissa_bits = 52,
585
            exponent_bits = 11,
586
            offset = 44,
587
            bits_ty = u64,
588
            bits_ty_signed = i64,
589
            double_ty = u128,
590
            float_ty = f64,
591
0
            is_nan = return Self::ZERO,
592
0
            is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX },
593
        )
594
0
    }
595
596
    /// Creates a new `Duration` from the specified number of seconds
597
    /// represented as `f32`. Any values that are out of bounds are saturated at
598
    /// the minimum or maximum respectively. `NaN` gets turned into a `Duration`
599
    /// of 0 seconds.
600
    ///
601
    /// ```rust
602
    /// # use time::{Duration, ext::NumericalDuration};
603
    /// assert_eq!(Duration::saturating_seconds_f32(0.5), 0.5.seconds());
604
    /// assert_eq!(Duration::saturating_seconds_f32(-0.5), (-0.5).seconds());
605
    /// assert_eq!(
606
    ///     Duration::saturating_seconds_f32(f32::NAN),
607
    ///     Duration::new(0, 0),
608
    /// );
609
    /// assert_eq!(
610
    ///     Duration::saturating_seconds_f32(f32::NEG_INFINITY),
611
    ///     Duration::MIN,
612
    /// );
613
    /// assert_eq!(
614
    ///     Duration::saturating_seconds_f32(f32::INFINITY),
615
    ///     Duration::MAX,
616
    /// );
617
    /// ```
618
0
    pub fn saturating_seconds_f32(seconds: f32) -> Self {
619
0
        try_from_secs!(
620
0
            secs = seconds,
621
0
            mantissa_bits = 23,
622
            exponent_bits = 8,
623
            offset = 41,
624
            bits_ty = u32,
625
            bits_ty_signed = i32,
626
            double_ty = u64,
627
            float_ty = f32,
628
0
            is_nan = return Self::ZERO,
629
0
            is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX },
630
        )
631
0
    }
632
633
    /// Creates a new `Duration` from the specified number of seconds
634
    /// represented as `f64`. Returns `None` if the `Duration` can't be
635
    /// represented.
636
    ///
637
    /// ```rust
638
    /// # use time::{Duration, ext::NumericalDuration};
639
    /// assert_eq!(Duration::checked_seconds_f64(0.5), Some(0.5.seconds()));
640
    /// assert_eq!(Duration::checked_seconds_f64(-0.5), Some((-0.5).seconds()));
641
    /// assert_eq!(Duration::checked_seconds_f64(f64::NAN), None);
642
    /// assert_eq!(Duration::checked_seconds_f64(f64::NEG_INFINITY), None);
643
    /// assert_eq!(Duration::checked_seconds_f64(f64::INFINITY), None);
644
    /// ```
645
0
    pub fn checked_seconds_f64(seconds: f64) -> Option<Self> {
646
0
        Some(try_from_secs!(
647
0
            secs = seconds,
648
0
            mantissa_bits = 52,
649
            exponent_bits = 11,
650
            offset = 44,
651
            bits_ty = u64,
652
            bits_ty_signed = i64,
653
            double_ty = u128,
654
            float_ty = f64,
655
0
            is_nan = return None,
656
0
            is_overflow = return None,
657
        ))
658
0
    }
659
660
    /// Creates a new `Duration` from the specified number of seconds
661
    /// represented as `f32`. Returns `None` if the `Duration` can't be
662
    /// represented.
663
    ///
664
    /// ```rust
665
    /// # use time::{Duration, ext::NumericalDuration};
666
    /// assert_eq!(Duration::checked_seconds_f32(0.5), Some(0.5.seconds()));
667
    /// assert_eq!(Duration::checked_seconds_f32(-0.5), Some((-0.5).seconds()));
668
    /// assert_eq!(Duration::checked_seconds_f32(f32::NAN), None);
669
    /// assert_eq!(Duration::checked_seconds_f32(f32::NEG_INFINITY), None);
670
    /// assert_eq!(Duration::checked_seconds_f32(f32::INFINITY), None);
671
    /// ```
672
0
    pub fn checked_seconds_f32(seconds: f32) -> Option<Self> {
673
0
        Some(try_from_secs!(
674
0
            secs = seconds,
675
0
            mantissa_bits = 23,
676
            exponent_bits = 8,
677
            offset = 41,
678
            bits_ty = u32,
679
            bits_ty_signed = i32,
680
            double_ty = u64,
681
            float_ty = f32,
682
0
            is_nan = return None,
683
0
            is_overflow = return None,
684
        ))
685
0
    }
686
687
    /// Create a new `Duration` with the given number of milliseconds.
688
    ///
689
    /// ```rust
690
    /// # use time::{Duration, ext::NumericalDuration};
691
    /// assert_eq!(Duration::milliseconds(1), 1_000.microseconds());
692
    /// assert_eq!(Duration::milliseconds(-1), (-1_000).microseconds());
693
    /// ```
694
0
    pub const fn milliseconds(milliseconds: i64) -> Self {
695
0
        // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
696
0
        unsafe {
697
0
            Self::new_unchecked(
698
0
                milliseconds / Millisecond::per(Second) as i64,
699
0
                (milliseconds % Millisecond::per(Second) as i64
700
0
                    * Nanosecond::per(Millisecond) as i64) as _,
701
0
            )
702
0
        }
703
0
    }
704
705
    /// Create a new `Duration` with the given number of microseconds.
706
    ///
707
    /// ```rust
708
    /// # use time::{Duration, ext::NumericalDuration};
709
    /// assert_eq!(Duration::microseconds(1), 1_000.nanoseconds());
710
    /// assert_eq!(Duration::microseconds(-1), (-1_000).nanoseconds());
711
    /// ```
712
0
    pub const fn microseconds(microseconds: i64) -> Self {
713
0
        // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
714
0
        unsafe {
715
0
            Self::new_unchecked(
716
0
                microseconds / Microsecond::per(Second) as i64,
717
0
                (microseconds % Microsecond::per(Second) as i64
718
0
                    * Nanosecond::per(Microsecond) as i64) as _,
719
0
            )
720
0
        }
721
0
    }
722
723
    /// Create a new `Duration` with the given number of nanoseconds.
724
    ///
725
    /// ```rust
726
    /// # use time::{Duration, ext::NumericalDuration};
727
    /// assert_eq!(Duration::nanoseconds(1), 1.microseconds() / 1_000);
728
    /// assert_eq!(Duration::nanoseconds(-1), (-1).microseconds() / 1_000);
729
    /// ```
730
0
    pub const fn nanoseconds(nanoseconds: i64) -> Self {
731
0
        // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
732
0
        unsafe {
733
0
            Self::new_unchecked(
734
0
                nanoseconds / Nanosecond::per(Second) as i64,
735
0
                (nanoseconds % Nanosecond::per(Second) as i64) as _,
736
0
            )
737
0
        }
738
0
    }
739
740
    /// Create a new `Duration` with the given number of nanoseconds.
741
    ///
742
    /// As the input range cannot be fully mapped to the output, this should only be used where it's
743
    /// known to result in a valid value.
744
0
    pub(crate) const fn nanoseconds_i128(nanoseconds: i128) -> Self {
745
0
        let seconds = nanoseconds / Nanosecond::per(Second) as i128;
746
0
        let nanoseconds = nanoseconds % Nanosecond::per(Second) as i128;
747
0
748
0
        if seconds > i64::MAX as i128 || seconds < i64::MIN as i128 {
749
0
            crate::expect_failed("overflow constructing `time::Duration`");
750
0
        }
751
0
752
0
        // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
753
0
        unsafe { Self::new_unchecked(seconds as _, nanoseconds as _) }
754
0
    }
755
    // endregion constructors
756
757
    // region: getters
758
    /// Get the number of whole weeks in the duration.
759
    ///
760
    /// ```rust
761
    /// # use time::ext::NumericalDuration;
762
    /// assert_eq!(1.weeks().whole_weeks(), 1);
763
    /// assert_eq!((-1).weeks().whole_weeks(), -1);
764
    /// assert_eq!(6.days().whole_weeks(), 0);
765
    /// assert_eq!((-6).days().whole_weeks(), 0);
766
    /// ```
767
0
    pub const fn whole_weeks(self) -> i64 {
768
0
        self.whole_seconds() / Second::per(Week) as i64
769
0
    }
770
771
    /// Get the number of whole days in the duration.
772
    ///
773
    /// ```rust
774
    /// # use time::ext::NumericalDuration;
775
    /// assert_eq!(1.days().whole_days(), 1);
776
    /// assert_eq!((-1).days().whole_days(), -1);
777
    /// assert_eq!(23.hours().whole_days(), 0);
778
    /// assert_eq!((-23).hours().whole_days(), 0);
779
    /// ```
780
0
    pub const fn whole_days(self) -> i64 {
781
0
        self.whole_seconds() / Second::per(Day) as i64
782
0
    }
783
784
    /// Get the number of whole hours in the duration.
785
    ///
786
    /// ```rust
787
    /// # use time::ext::NumericalDuration;
788
    /// assert_eq!(1.hours().whole_hours(), 1);
789
    /// assert_eq!((-1).hours().whole_hours(), -1);
790
    /// assert_eq!(59.minutes().whole_hours(), 0);
791
    /// assert_eq!((-59).minutes().whole_hours(), 0);
792
    /// ```
793
0
    pub const fn whole_hours(self) -> i64 {
794
0
        self.whole_seconds() / Second::per(Hour) as i64
795
0
    }
796
797
    /// Get the number of whole minutes in the duration.
798
    ///
799
    /// ```rust
800
    /// # use time::ext::NumericalDuration;
801
    /// assert_eq!(1.minutes().whole_minutes(), 1);
802
    /// assert_eq!((-1).minutes().whole_minutes(), -1);
803
    /// assert_eq!(59.seconds().whole_minutes(), 0);
804
    /// assert_eq!((-59).seconds().whole_minutes(), 0);
805
    /// ```
806
0
    pub const fn whole_minutes(self) -> i64 {
807
0
        self.whole_seconds() / Second::per(Minute) as i64
808
0
    }
809
810
    /// Get the number of whole seconds in the duration.
811
    ///
812
    /// ```rust
813
    /// # use time::ext::NumericalDuration;
814
    /// assert_eq!(1.seconds().whole_seconds(), 1);
815
    /// assert_eq!((-1).seconds().whole_seconds(), -1);
816
    /// assert_eq!(1.minutes().whole_seconds(), 60);
817
    /// assert_eq!((-1).minutes().whole_seconds(), -60);
818
    /// ```
819
0
    pub const fn whole_seconds(self) -> i64 {
820
0
        self.seconds
821
0
    }
822
823
    /// Get the number of fractional seconds in the duration.
824
    ///
825
    /// ```rust
826
    /// # use time::ext::NumericalDuration;
827
    /// assert_eq!(1.5.seconds().as_seconds_f64(), 1.5);
828
    /// assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5);
829
    /// ```
830
0
    pub fn as_seconds_f64(self) -> f64 {
831
0
        self.seconds as f64 + self.nanoseconds.get() as f64 / Nanosecond::per(Second) as f64
832
0
    }
833
834
    /// Get the number of fractional seconds in the duration.
835
    ///
836
    /// ```rust
837
    /// # use time::ext::NumericalDuration;
838
    /// assert_eq!(1.5.seconds().as_seconds_f32(), 1.5);
839
    /// assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5);
840
    /// ```
841
0
    pub fn as_seconds_f32(self) -> f32 {
842
0
        self.seconds as f32 + self.nanoseconds.get() as f32 / Nanosecond::per(Second) as f32
843
0
    }
844
845
    /// Get the number of whole milliseconds in the duration.
846
    ///
847
    /// ```rust
848
    /// # use time::ext::NumericalDuration;
849
    /// assert_eq!(1.seconds().whole_milliseconds(), 1_000);
850
    /// assert_eq!((-1).seconds().whole_milliseconds(), -1_000);
851
    /// assert_eq!(1.milliseconds().whole_milliseconds(), 1);
852
    /// assert_eq!((-1).milliseconds().whole_milliseconds(), -1);
853
    /// ```
854
0
    pub const fn whole_milliseconds(self) -> i128 {
855
0
        self.seconds as i128 * Millisecond::per(Second) as i128
856
0
            + self.nanoseconds.get() as i128 / Nanosecond::per(Millisecond) as i128
857
0
    }
858
859
    /// Get the number of milliseconds past the number of whole seconds.
860
    ///
861
    /// Always in the range `-999..=999`.
862
    ///
863
    /// ```rust
864
    /// # use time::ext::NumericalDuration;
865
    /// assert_eq!(1.4.seconds().subsec_milliseconds(), 400);
866
    /// assert_eq!((-1.4).seconds().subsec_milliseconds(), -400);
867
    /// ```
868
    // Allow the lint, as the value is guaranteed to be less than 1000.
869
0
    pub const fn subsec_milliseconds(self) -> i16 {
870
0
        (self.nanoseconds.get() / Nanosecond::per(Millisecond) as i32) as _
871
0
    }
872
873
    /// Get the number of whole microseconds in the duration.
874
    ///
875
    /// ```rust
876
    /// # use time::ext::NumericalDuration;
877
    /// assert_eq!(1.milliseconds().whole_microseconds(), 1_000);
878
    /// assert_eq!((-1).milliseconds().whole_microseconds(), -1_000);
879
    /// assert_eq!(1.microseconds().whole_microseconds(), 1);
880
    /// assert_eq!((-1).microseconds().whole_microseconds(), -1);
881
    /// ```
882
0
    pub const fn whole_microseconds(self) -> i128 {
883
0
        self.seconds as i128 * Microsecond::per(Second) as i128
884
0
            + self.nanoseconds.get() as i128 / Nanosecond::per(Microsecond) as i128
885
0
    }
886
887
    /// Get the number of microseconds past the number of whole seconds.
888
    ///
889
    /// Always in the range `-999_999..=999_999`.
890
    ///
891
    /// ```rust
892
    /// # use time::ext::NumericalDuration;
893
    /// assert_eq!(1.0004.seconds().subsec_microseconds(), 400);
894
    /// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400);
895
    /// ```
896
0
    pub const fn subsec_microseconds(self) -> i32 {
897
0
        self.nanoseconds.get() / Nanosecond::per(Microsecond) as i32
898
0
    }
899
900
    /// Get the number of nanoseconds in the duration.
901
    ///
902
    /// ```rust
903
    /// # use time::ext::NumericalDuration;
904
    /// assert_eq!(1.microseconds().whole_nanoseconds(), 1_000);
905
    /// assert_eq!((-1).microseconds().whole_nanoseconds(), -1_000);
906
    /// assert_eq!(1.nanoseconds().whole_nanoseconds(), 1);
907
    /// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1);
908
    /// ```
909
0
    pub const fn whole_nanoseconds(self) -> i128 {
910
0
        self.seconds as i128 * Nanosecond::per(Second) as i128 + self.nanoseconds.get() as i128
911
0
    }
912
913
    /// Get the number of nanoseconds past the number of whole seconds.
914
    ///
915
    /// The returned value will always be in the range `-999_999_999..=999_999_999`.
916
    ///
917
    /// ```rust
918
    /// # use time::ext::NumericalDuration;
919
    /// assert_eq!(1.000_000_400.seconds().subsec_nanoseconds(), 400);
920
    /// assert_eq!((-1.000_000_400).seconds().subsec_nanoseconds(), -400);
921
    /// ```
922
0
    pub const fn subsec_nanoseconds(self) -> i32 {
923
0
        self.nanoseconds.get()
924
0
    }
925
926
    /// Get the number of nanoseconds past the number of whole seconds.
927
    #[cfg(feature = "quickcheck")]
928
    pub(crate) const fn subsec_nanoseconds_ranged(self) -> Nanoseconds {
929
        self.nanoseconds
930
    }
931
    // endregion getters
932
933
    // region: checked arithmetic
934
    /// Computes `self + rhs`, returning `None` if an overflow occurred.
935
    ///
936
    /// ```rust
937
    /// # use time::{Duration, ext::NumericalDuration};
938
    /// assert_eq!(5.seconds().checked_add(5.seconds()), Some(10.seconds()));
939
    /// assert_eq!(Duration::MAX.checked_add(1.nanoseconds()), None);
940
    /// assert_eq!((-5).seconds().checked_add(5.seconds()), Some(0.seconds()));
941
    /// ```
942
0
    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
943
0
        let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds));
944
0
        let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
945
0
946
0
        if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
947
0
            nanoseconds -= Nanosecond::per(Second) as i32;
948
0
            seconds = const_try_opt!(seconds.checked_add(1));
949
0
        } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
950
        {
951
0
            nanoseconds += Nanosecond::per(Second) as i32;
952
0
            seconds = const_try_opt!(seconds.checked_sub(1));
953
0
        }
954
955
        // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
956
0
        unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
957
0
    }
958
959
    /// Computes `self - rhs`, returning `None` if an overflow occurred.
960
    ///
961
    /// ```rust
962
    /// # use time::{Duration, ext::NumericalDuration};
963
    /// assert_eq!(5.seconds().checked_sub(5.seconds()), Some(Duration::ZERO));
964
    /// assert_eq!(Duration::MIN.checked_sub(1.nanoseconds()), None);
965
    /// assert_eq!(5.seconds().checked_sub(10.seconds()), Some((-5).seconds()));
966
    /// ```
967
0
    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
968
0
        let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds));
969
0
        let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
970
0
971
0
        if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
972
0
            nanoseconds -= Nanosecond::per(Second) as i32;
973
0
            seconds = const_try_opt!(seconds.checked_add(1));
974
0
        } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
975
        {
976
0
            nanoseconds += Nanosecond::per(Second) as i32;
977
0
            seconds = const_try_opt!(seconds.checked_sub(1));
978
0
        }
979
980
        // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
981
0
        unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
982
0
    }
983
984
    /// Computes `self * rhs`, returning `None` if an overflow occurred.
985
    ///
986
    /// ```rust
987
    /// # use time::{Duration, ext::NumericalDuration};
988
    /// assert_eq!(5.seconds().checked_mul(2), Some(10.seconds()));
989
    /// assert_eq!(5.seconds().checked_mul(-2), Some((-10).seconds()));
990
    /// assert_eq!(5.seconds().checked_mul(0), Some(0.seconds()));
991
    /// assert_eq!(Duration::MAX.checked_mul(2), None);
992
    /// assert_eq!(Duration::MIN.checked_mul(2), None);
993
    /// ```
994
0
    pub const fn checked_mul(self, rhs: i32) -> Option<Self> {
995
0
        // Multiply nanoseconds as i64, because it cannot overflow that way.
996
0
        let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
997
0
        let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
998
0
        let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as _;
999
0
        let seconds = const_try_opt!(
1000
0
            const_try_opt!(self.seconds.checked_mul(rhs as _)).checked_add(extra_secs)
1001
        );
1002
1003
        // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
1004
0
        unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
1005
0
    }
1006
1007
    /// Computes `self / rhs`, returning `None` if `rhs == 0` or if the result would overflow.
1008
    ///
1009
    /// ```rust
1010
    /// # use time::ext::NumericalDuration;
1011
    /// assert_eq!(10.seconds().checked_div(2), Some(5.seconds()));
1012
    /// assert_eq!(10.seconds().checked_div(-2), Some((-5).seconds()));
1013
    /// assert_eq!(1.seconds().checked_div(0), None);
1014
    /// ```
1015
0
    pub const fn checked_div(self, rhs: i32) -> Option<Self> {
1016
0
        let (secs, extra_secs) = (
1017
0
            const_try_opt!(self.seconds.checked_div(rhs as i64)),
1018
0
            self.seconds % (rhs as i64),
1019
0
        );
1020
0
        let (mut nanos, extra_nanos) = (self.nanoseconds.get() / rhs, self.nanoseconds.get() % rhs);
1021
0
        nanos += ((extra_secs * (Nanosecond::per(Second) as i64) + extra_nanos as i64)
1022
0
            / (rhs as i64)) as i32;
1023
0
1024
0
        // Safety: `nanoseconds` is in range.
1025
0
        unsafe { Some(Self::new_unchecked(secs, nanos)) }
1026
0
    }
1027
1028
    /// Computes `-self`, returning `None` if the result would overflow.
1029
    ///
1030
    /// ```rust
1031
    /// # use time::ext::NumericalDuration;
1032
    /// # use time::Duration;
1033
    /// assert_eq!(5.seconds().checked_neg(), Some((-5).seconds()));
1034
    /// assert_eq!(Duration::MIN.checked_neg(), None);
1035
    /// ```
1036
0
    pub const fn checked_neg(self) -> Option<Self> {
1037
0
        if self.seconds == i64::MIN {
1038
0
            None
1039
        } else {
1040
0
            Some(Self::new_ranged_unchecked(
1041
0
                -self.seconds,
1042
0
                self.nanoseconds.neg(),
1043
0
            ))
1044
        }
1045
0
    }
1046
    // endregion checked arithmetic
1047
1048
    // region: saturating arithmetic
1049
    /// Computes `self + rhs`, saturating if an overflow occurred.
1050
    ///
1051
    /// ```rust
1052
    /// # use time::{Duration, ext::NumericalDuration};
1053
    /// assert_eq!(5.seconds().saturating_add(5.seconds()), 10.seconds());
1054
    /// assert_eq!(Duration::MAX.saturating_add(1.nanoseconds()), Duration::MAX);
1055
    /// assert_eq!(
1056
    ///     Duration::MIN.saturating_add((-1).nanoseconds()),
1057
    ///     Duration::MIN
1058
    /// );
1059
    /// assert_eq!((-5).seconds().saturating_add(5.seconds()), Duration::ZERO);
1060
    /// ```
1061
0
    pub const fn saturating_add(self, rhs: Self) -> Self {
1062
0
        let (mut seconds, overflow) = self.seconds.overflowing_add(rhs.seconds);
1063
0
        if overflow {
1064
0
            if self.seconds > 0 {
1065
0
                return Self::MAX;
1066
0
            }
1067
0
            return Self::MIN;
1068
0
        }
1069
0
        let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
1070
0
1071
0
        if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
1072
0
            nanoseconds -= Nanosecond::per(Second) as i32;
1073
0
            seconds = match seconds.checked_add(1) {
1074
0
                Some(seconds) => seconds,
1075
0
                None => return Self::MAX,
1076
            };
1077
0
        } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
1078
        {
1079
0
            nanoseconds += Nanosecond::per(Second) as i32;
1080
0
            seconds = match seconds.checked_sub(1) {
1081
0
                Some(seconds) => seconds,
1082
0
                None => return Self::MIN,
1083
            };
1084
0
        }
1085
1086
        // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
1087
0
        unsafe { Self::new_unchecked(seconds, nanoseconds) }
1088
0
    }
1089
1090
    /// Computes `self - rhs`, saturating if an overflow occurred.
1091
    ///
1092
    /// ```rust
1093
    /// # use time::{Duration, ext::NumericalDuration};
1094
    /// assert_eq!(5.seconds().saturating_sub(5.seconds()), Duration::ZERO);
1095
    /// assert_eq!(Duration::MIN.saturating_sub(1.nanoseconds()), Duration::MIN);
1096
    /// assert_eq!(
1097
    ///     Duration::MAX.saturating_sub((-1).nanoseconds()),
1098
    ///     Duration::MAX
1099
    /// );
1100
    /// assert_eq!(5.seconds().saturating_sub(10.seconds()), (-5).seconds());
1101
    /// ```
1102
0
    pub const fn saturating_sub(self, rhs: Self) -> Self {
1103
0
        let (mut seconds, overflow) = self.seconds.overflowing_sub(rhs.seconds);
1104
0
        if overflow {
1105
0
            if self.seconds > 0 {
1106
0
                return Self::MAX;
1107
0
            }
1108
0
            return Self::MIN;
1109
0
        }
1110
0
        let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
1111
0
1112
0
        if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
1113
0
            nanoseconds -= Nanosecond::per(Second) as i32;
1114
0
            seconds = match seconds.checked_add(1) {
1115
0
                Some(seconds) => seconds,
1116
0
                None => return Self::MAX,
1117
            };
1118
0
        } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
1119
        {
1120
0
            nanoseconds += Nanosecond::per(Second) as i32;
1121
0
            seconds = match seconds.checked_sub(1) {
1122
0
                Some(seconds) => seconds,
1123
0
                None => return Self::MIN,
1124
            };
1125
0
        }
1126
1127
        // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
1128
0
        unsafe { Self::new_unchecked(seconds, nanoseconds) }
1129
0
    }
1130
1131
    /// Computes `self * rhs`, saturating if an overflow occurred.
1132
    ///
1133
    /// ```rust
1134
    /// # use time::{Duration, ext::NumericalDuration};
1135
    /// assert_eq!(5.seconds().saturating_mul(2), 10.seconds());
1136
    /// assert_eq!(5.seconds().saturating_mul(-2), (-10).seconds());
1137
    /// assert_eq!(5.seconds().saturating_mul(0), Duration::ZERO);
1138
    /// assert_eq!(Duration::MAX.saturating_mul(2), Duration::MAX);
1139
    /// assert_eq!(Duration::MIN.saturating_mul(2), Duration::MIN);
1140
    /// assert_eq!(Duration::MAX.saturating_mul(-2), Duration::MIN);
1141
    /// assert_eq!(Duration::MIN.saturating_mul(-2), Duration::MAX);
1142
    /// ```
1143
0
    pub const fn saturating_mul(self, rhs: i32) -> Self {
1144
0
        // Multiply nanoseconds as i64, because it cannot overflow that way.
1145
0
        let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
1146
0
        let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
1147
0
        let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as _;
1148
0
        let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as _);
1149
0
        if overflow1 {
1150
0
            if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 {
1151
0
                return Self::MAX;
1152
0
            }
1153
0
            return Self::MIN;
1154
0
        }
1155
0
        let (seconds, overflow2) = seconds.overflowing_add(extra_secs);
1156
0
        if overflow2 {
1157
0
            if self.seconds > 0 && rhs > 0 {
1158
0
                return Self::MAX;
1159
0
            }
1160
0
            return Self::MIN;
1161
0
        }
1162
0
1163
0
        // Safety: `nanoseconds` is guaranteed to be in range because of to the modulus above.
1164
0
        unsafe { Self::new_unchecked(seconds, nanoseconds) }
1165
0
    }
1166
    // endregion saturating arithmetic
1167
1168
    /// Runs a closure, returning the duration of time it took to run. The return value of the
1169
    /// closure is provided in the second part of the tuple.
1170
    #[doc(hidden)]
1171
    #[cfg(feature = "std")]
1172
    #[deprecated(
1173
        since = "0.3.32",
1174
        note = "extremely limited use case, not intended for benchmarking"
1175
    )]
1176
    #[allow(deprecated)]
1177
0
    pub fn time_fn<T>(f: impl FnOnce() -> T) -> (Self, T) {
1178
0
        let start = Instant::now();
1179
0
        let return_value = f();
1180
0
        let end = Instant::now();
1181
0
1182
0
        (end - start, return_value)
1183
0
    }
1184
}
1185
1186
// region: trait impls
1187
/// The format returned by this implementation is not stable and must not be relied upon.
1188
///
1189
/// By default this produces an exact, full-precision printout of the duration.
1190
/// For a concise, rounded printout instead, you can use the `.N` format specifier:
1191
///
1192
/// ```
1193
/// # use time::Duration;
1194
/// #
1195
/// let duration = Duration::new(123456, 789011223);
1196
/// println!("{duration:.3}");
1197
/// ```
1198
///
1199
/// For the purposes of this implementation, a day is exactly 24 hours and a minute is exactly 60
1200
/// seconds.
1201
impl fmt::Display for Duration {
1202
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1203
0
        if self.is_negative() {
1204
0
            f.write_str("-")?;
1205
0
        }
1206
1207
0
        if let Some(_precision) = f.precision() {
1208
            // Concise, rounded representation.
1209
1210
0
            if self.is_zero() {
1211
                // Write a zero value with the requested precision.
1212
0
                return (0.).fmt(f).and_then(|_| f.write_str("s"));
1213
0
            }
1214
1215
            /// Format the first item that produces a value greater than 1 and then break.
1216
            macro_rules! item {
1217
                ($name:literal, $value:expr) => {
1218
                    let value = $value;
1219
                    if value >= 1.0 {
1220
0
                        return value.fmt(f).and_then(|_| f.write_str($name));
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#1}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#2}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#3}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#4}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#5}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#6}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#7}
1221
                    }
1222
                };
1223
            }
1224
1225
            // Even if this produces a de-normal float, because we're rounding we don't really care.
1226
0
            let seconds = self.unsigned_abs().as_secs_f64();
1227
0
1228
0
            item!("d", seconds / Second::per(Day) as f64);
1229
0
            item!("h", seconds / Second::per(Hour) as f64);
1230
0
            item!("m", seconds / Second::per(Minute) as f64);
1231
0
            item!("s", seconds);
1232
0
            item!("ms", seconds * Millisecond::per(Second) as f64);
1233
0
            item!("µs", seconds * Microsecond::per(Second) as f64);
1234
0
            item!("ns", seconds * Nanosecond::per(Second) as f64);
1235
        } else {
1236
            // Precise, but verbose representation.
1237
1238
0
            if self.is_zero() {
1239
0
                return f.write_str("0s");
1240
0
            }
1241
1242
            /// Format a single item.
1243
            macro_rules! item {
1244
                ($name:literal, $value:expr) => {
1245
                    match $value {
1246
                        0 => Ok(()),
1247
0
                        value => value.fmt(f).and_then(|_| f.write_str($name)),
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#8}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#9}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#10}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#11}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#12}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#13}
Unexecuted instantiation: <time::duration::Duration as core::fmt::Display>::fmt::{closure#14}
1248
                    }
1249
                };
1250
            }
1251
1252
0
            let seconds = self.seconds.unsigned_abs();
1253
0
            let nanoseconds = self.nanoseconds.get().unsigned_abs();
1254
1255
0
            item!("d", seconds / Second::per(Day).extend::<u64>())?;
1256
0
            item!(
1257
                "h",
1258
0
                seconds / Second::per(Hour).extend::<u64>() % Hour::per(Day).extend::<u64>()
1259
0
            )?;
1260
0
            item!(
1261
                "m",
1262
0
                seconds / Second::per(Minute).extend::<u64>() % Minute::per(Hour).extend::<u64>()
1263
0
            )?;
1264
0
            item!("s", seconds % Second::per(Minute).extend::<u64>())?;
1265
0
            item!("ms", nanoseconds / Nanosecond::per(Millisecond))?;
1266
0
            item!(
1267
                "µs",
1268
0
                nanoseconds / Nanosecond::per(Microsecond).extend::<u32>()
1269
0
                    % Microsecond::per(Millisecond).extend::<u32>()
1270
0
            )?;
1271
0
            item!(
1272
                "ns",
1273
0
                nanoseconds % Nanosecond::per(Microsecond).extend::<u32>()
1274
0
            )?;
1275
        }
1276
1277
0
        Ok(())
1278
0
    }
1279
}
1280
1281
impl TryFrom<StdDuration> for Duration {
1282
    type Error = error::ConversionRange;
1283
1284
0
    fn try_from(original: StdDuration) -> Result<Self, error::ConversionRange> {
1285
0
        Ok(Self::new(
1286
0
            original
1287
0
                .as_secs()
1288
0
                .try_into()
1289
0
                .map_err(|_| error::ConversionRange)?,
1290
0
            original.subsec_nanos().cast_signed(),
1291
        ))
1292
0
    }
1293
}
1294
1295
impl TryFrom<Duration> for StdDuration {
1296
    type Error = error::ConversionRange;
1297
1298
0
    fn try_from(duration: Duration) -> Result<Self, error::ConversionRange> {
1299
0
        Ok(Self::new(
1300
0
            duration
1301
0
                .seconds
1302
0
                .try_into()
1303
0
                .map_err(|_| error::ConversionRange)?,
1304
0
            duration
1305
0
                .nanoseconds
1306
0
                .get()
1307
0
                .try_into()
1308
0
                .map_err(|_| error::ConversionRange)?,
1309
        ))
1310
0
    }
1311
}
1312
1313
impl Add for Duration {
1314
    type Output = Self;
1315
1316
    /// # Panics
1317
    ///
1318
    /// This may panic if an overflow occurs.
1319
0
    fn add(self, rhs: Self) -> Self::Output {
1320
0
        self.checked_add(rhs)
1321
0
            .expect("overflow when adding durations")
1322
0
    }
1323
}
1324
1325
impl Add<StdDuration> for Duration {
1326
    type Output = Self;
1327
1328
    /// # Panics
1329
    ///
1330
    /// This may panic if an overflow occurs.
1331
0
    fn add(self, std_duration: StdDuration) -> Self::Output {
1332
0
        self + Self::try_from(std_duration)
1333
0
            .expect("overflow converting `std::time::Duration` to `time::Duration`")
1334
0
    }
1335
}
1336
1337
impl Add<Duration> for StdDuration {
1338
    type Output = Duration;
1339
1340
0
    fn add(self, rhs: Duration) -> Self::Output {
1341
0
        rhs + self
1342
0
    }
1343
}
1344
1345
impl_add_assign!(Duration: Self, StdDuration);
1346
1347
impl AddAssign<Duration> for StdDuration {
1348
    /// # Panics
1349
    ///
1350
    /// This may panic if the resulting addition cannot be represented.
1351
0
    fn add_assign(&mut self, rhs: Duration) {
1352
0
        *self = (*self + rhs).try_into().expect(
1353
0
            "Cannot represent a resulting duration in std. Try `let x = x + rhs;`, which will \
1354
0
             change the type.",
1355
0
        );
1356
0
    }
1357
}
1358
1359
impl Neg for Duration {
1360
    type Output = Self;
1361
1362
0
    fn neg(self) -> Self::Output {
1363
0
        self.checked_neg().expect("overflow when negating duration")
1364
0
    }
1365
}
1366
1367
impl Sub for Duration {
1368
    type Output = Self;
1369
1370
    /// # Panics
1371
    ///
1372
    /// This may panic if an overflow occurs.
1373
0
    fn sub(self, rhs: Self) -> Self::Output {
1374
0
        self.checked_sub(rhs)
1375
0
            .expect("overflow when subtracting durations")
1376
0
    }
1377
}
1378
1379
impl Sub<StdDuration> for Duration {
1380
    type Output = Self;
1381
1382
    /// # Panics
1383
    ///
1384
    /// This may panic if an overflow occurs.
1385
0
    fn sub(self, rhs: StdDuration) -> Self::Output {
1386
0
        self - Self::try_from(rhs)
1387
0
            .expect("overflow converting `std::time::Duration` to `time::Duration`")
1388
0
    }
1389
}
1390
1391
impl Sub<Duration> for StdDuration {
1392
    type Output = Duration;
1393
1394
    /// # Panics
1395
    ///
1396
    /// This may panic if an overflow occurs.
1397
0
    fn sub(self, rhs: Duration) -> Self::Output {
1398
0
        Duration::try_from(self)
1399
0
            .expect("overflow converting `std::time::Duration` to `time::Duration`")
1400
0
            - rhs
1401
0
    }
1402
}
1403
1404
impl_sub_assign!(Duration: Self, StdDuration);
1405
1406
impl SubAssign<Duration> for StdDuration {
1407
    /// # Panics
1408
    ///
1409
    /// This may panic if the resulting subtraction can not be represented.
1410
0
    fn sub_assign(&mut self, rhs: Duration) {
1411
0
        *self = (*self - rhs).try_into().expect(
1412
0
            "Cannot represent a resulting duration in std. Try `let x = x - rhs;`, which will \
1413
0
             change the type.",
1414
0
        );
1415
0
    }
1416
}
1417
1418
/// Implement `Mul` (reflexively) and `Div` for `Duration` for various types.
1419
macro_rules! duration_mul_div_int {
1420
    ($($type:ty),+) => {$(
1421
        impl Mul<$type> for Duration {
1422
            type Output = Self;
1423
1424
0
            fn mul(self, rhs: $type) -> Self::Output {
1425
0
                Self::nanoseconds_i128(
1426
0
                    self.whole_nanoseconds()
1427
0
                        .checked_mul(rhs.cast_signed().extend::<i128>())
1428
0
                        .expect("overflow when multiplying duration")
1429
0
                )
1430
0
            }
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Mul<i8>>::mul
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Mul<i16>>::mul
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Mul<i32>>::mul
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Mul<u8>>::mul
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Mul<u16>>::mul
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Mul<u32>>::mul
1431
        }
1432
1433
        impl Mul<Duration> for $type {
1434
            type Output = Duration;
1435
1436
0
            fn mul(self, rhs: Duration) -> Self::Output {
1437
0
                rhs * self
1438
0
            }
Unexecuted instantiation: <i8 as core::ops::arith::Mul<time::duration::Duration>>::mul
Unexecuted instantiation: <i16 as core::ops::arith::Mul<time::duration::Duration>>::mul
Unexecuted instantiation: <i32 as core::ops::arith::Mul<time::duration::Duration>>::mul
Unexecuted instantiation: <u8 as core::ops::arith::Mul<time::duration::Duration>>::mul
Unexecuted instantiation: <u16 as core::ops::arith::Mul<time::duration::Duration>>::mul
Unexecuted instantiation: <u32 as core::ops::arith::Mul<time::duration::Duration>>::mul
1439
        }
1440
1441
        impl Div<$type> for Duration {
1442
            type Output = Self;
1443
1444
0
            fn div(self, rhs: $type) -> Self::Output {
1445
0
                Self::nanoseconds_i128(
1446
0
                    self.whole_nanoseconds() / rhs.cast_signed().extend::<i128>()
1447
0
                )
1448
0
            }
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Div<i8>>::div
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Div<i16>>::div
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Div<i32>>::div
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Div<u8>>::div
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Div<u16>>::div
Unexecuted instantiation: <time::duration::Duration as core::ops::arith::Div<u32>>::div
1449
        }
1450
    )+};
1451
}
1452
duration_mul_div_int![i8, i16, i32, u8, u16, u32];
1453
1454
impl Mul<f32> for Duration {
1455
    type Output = Self;
1456
1457
0
    fn mul(self, rhs: f32) -> Self::Output {
1458
0
        Self::seconds_f32(self.as_seconds_f32() * rhs)
1459
0
    }
1460
}
1461
1462
impl Mul<Duration> for f32 {
1463
    type Output = Duration;
1464
1465
0
    fn mul(self, rhs: Duration) -> Self::Output {
1466
0
        rhs * self
1467
0
    }
1468
}
1469
1470
impl Mul<f64> for Duration {
1471
    type Output = Self;
1472
1473
0
    fn mul(self, rhs: f64) -> Self::Output {
1474
0
        Self::seconds_f64(self.as_seconds_f64() * rhs)
1475
0
    }
1476
}
1477
1478
impl Mul<Duration> for f64 {
1479
    type Output = Duration;
1480
1481
0
    fn mul(self, rhs: Duration) -> Self::Output {
1482
0
        rhs * self
1483
0
    }
1484
}
1485
1486
impl_mul_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
1487
1488
impl Div<f32> for Duration {
1489
    type Output = Self;
1490
1491
0
    fn div(self, rhs: f32) -> Self::Output {
1492
0
        Self::seconds_f32(self.as_seconds_f32() / rhs)
1493
0
    }
1494
}
1495
1496
impl Div<f64> for Duration {
1497
    type Output = Self;
1498
1499
0
    fn div(self, rhs: f64) -> Self::Output {
1500
0
        Self::seconds_f64(self.as_seconds_f64() / rhs)
1501
0
    }
1502
}
1503
1504
impl_div_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
1505
1506
impl Div for Duration {
1507
    type Output = f64;
1508
1509
0
    fn div(self, rhs: Self) -> Self::Output {
1510
0
        self.as_seconds_f64() / rhs.as_seconds_f64()
1511
0
    }
1512
}
1513
1514
impl Div<StdDuration> for Duration {
1515
    type Output = f64;
1516
1517
0
    fn div(self, rhs: StdDuration) -> Self::Output {
1518
0
        self.as_seconds_f64() / rhs.as_secs_f64()
1519
0
    }
1520
}
1521
1522
impl Div<Duration> for StdDuration {
1523
    type Output = f64;
1524
1525
0
    fn div(self, rhs: Duration) -> Self::Output {
1526
0
        self.as_secs_f64() / rhs.as_seconds_f64()
1527
0
    }
1528
}
1529
1530
impl PartialEq<StdDuration> for Duration {
1531
0
    fn eq(&self, rhs: &StdDuration) -> bool {
1532
0
        Ok(*self) == Self::try_from(*rhs)
1533
0
    }
1534
}
1535
1536
impl PartialEq<Duration> for StdDuration {
1537
0
    fn eq(&self, rhs: &Duration) -> bool {
1538
0
        rhs == self
1539
0
    }
1540
}
1541
1542
impl PartialOrd<StdDuration> for Duration {
1543
0
    fn partial_cmp(&self, rhs: &StdDuration) -> Option<Ordering> {
1544
0
        if rhs.as_secs() > i64::MAX.cast_unsigned() {
1545
0
            return Some(Ordering::Less);
1546
0
        }
1547
0
1548
0
        Some(
1549
0
            self.seconds
1550
0
                .cmp(&rhs.as_secs().cast_signed())
1551
0
                .then_with(|| {
1552
0
                    self.nanoseconds
1553
0
                        .get()
1554
0
                        .cmp(&rhs.subsec_nanos().cast_signed())
1555
0
                }),
1556
0
        )
1557
0
    }
1558
}
1559
1560
impl PartialOrd<Duration> for StdDuration {
1561
0
    fn partial_cmp(&self, rhs: &Duration) -> Option<Ordering> {
1562
0
        rhs.partial_cmp(self).map(Ordering::reverse)
1563
0
    }
1564
}
1565
1566
impl Sum for Duration {
1567
0
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1568
0
        iter.reduce(|a, b| a + b).unwrap_or_default()
1569
0
    }
1570
}
1571
1572
impl<'a> Sum<&'a Self> for Duration {
1573
0
    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
1574
0
        iter.copied().sum()
1575
0
    }
1576
}
1577
// endregion trait impls