time/
duration.rs

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