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    #[allow(clippy::missing_docs_in_private_items)]
48    padding: Padding,
49}
50
51impl fmt::Debug for Duration {
52    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53        f.debug_struct("Duration")
54            .field("seconds", &self.seconds)
55            .field("nanoseconds", &self.nanoseconds)
56            .finish()
57    }
58}
59
60impl Default for Duration {
61    fn default() -> Self {
62        Self {
63            seconds: 0,
64            nanoseconds: Nanoseconds::new_static::<0>(),
65            padding: Padding::Optimize,
66        }
67    }
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.
77macro_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
191impl 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    pub const fn is_zero(self) -> bool {
281        self.seconds == 0 && self.nanoseconds.get() == 0
282    }
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    pub const fn is_negative(self) -> bool {
293        self.seconds < 0 || self.nanoseconds.get() < 0
294    }
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    pub const fn is_positive(self) -> bool {
305        self.seconds > 0 || self.nanoseconds.get() > 0
306    }
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    pub const fn abs(self) -> Self {
321        match self.seconds.checked_abs() {
322            Some(seconds) => Self::new_ranged_unchecked(seconds, self.nanoseconds.abs()),
323            None => Self::MAX,
324        }
325    }
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    pub const fn unsigned_abs(self) -> StdDuration {
337        StdDuration::new(
338            self.seconds.unsigned_abs(),
339            self.nanoseconds.get().unsigned_abs(),
340        )
341    }
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    pub(crate) const unsafe fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
354        Self::new_ranged_unchecked(
355            seconds,
356            // Safety: The caller must uphold the safety invariants.
357            unsafe { Nanoseconds::new_unchecked(nanoseconds) },
358        )
359    }
360
361    /// Create a new `Duration` without checking the validity of the components.
362    pub(crate) const fn new_ranged_unchecked(seconds: i64, nanoseconds: Nanoseconds) -> Self {
363        if seconds < 0 {
364            debug_assert!(nanoseconds.get() <= 0);
365        } else if seconds > 0 {
366            debug_assert!(nanoseconds.get() >= 0);
367        }
368
369        Self {
370            seconds,
371            nanoseconds,
372            padding: Padding::Optimize,
373        }
374    }
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    pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self {
390        seconds = expect_opt!(
391            seconds.checked_add(nanoseconds as i64 / Nanosecond::per(Second) as i64),
392            "overflow constructing `time::Duration`"
393        );
394        nanoseconds %= Nanosecond::per(Second) as i32;
395
396        if seconds > 0 && nanoseconds < 0 {
397            // `seconds` cannot overflow here because it is positive.
398            seconds -= 1;
399            nanoseconds += Nanosecond::per(Second) as i32;
400        } else if seconds < 0 && nanoseconds > 0 {
401            // `seconds` cannot overflow here because it is negative.
402            seconds += 1;
403            nanoseconds -= Nanosecond::per(Second) as i32;
404        }
405
406        // Safety: `nanoseconds` is in range due to the modulus above.
407        unsafe { Self::new_unchecked(seconds, nanoseconds) }
408    }
409
410    /// Create a new `Duration` with the provided seconds and nanoseconds.
411    pub(crate) const fn new_ranged(mut seconds: i64, mut nanoseconds: Nanoseconds) -> Self {
412        if seconds > 0 && nanoseconds.get() < 0 {
413            // `seconds` cannot overflow here because it is positive.
414            seconds -= 1;
415            // Safety: `nanoseconds` is negative with a maximum of 999,999,999, so adding a billion
416            // to it is guaranteed to result in an in-range value.
417            nanoseconds = unsafe {
418                Nanoseconds::new_unchecked(nanoseconds.get() + Nanosecond::per(Second) as i32)
419            };
420        } else if seconds < 0 && nanoseconds.get() > 0 {
421            // `seconds` cannot overflow here because it is negative.
422            seconds += 1;
423            // Safety: `nanoseconds` is positive with a minimum of -999,999,999, so subtracting a
424            // billion from it is guaranteed to result in an in-range value.
425            nanoseconds = unsafe {
426                Nanoseconds::new_unchecked(nanoseconds.get() - Nanosecond::per(Second) as i32)
427            };
428        }
429
430        Self::new_ranged_unchecked(seconds, nanoseconds)
431    }
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    pub const fn weeks(weeks: i64) -> Self {
445        Self::seconds(expect_opt!(
446            weeks.checked_mul(Second::per(Week) as _),
447            "overflow constructing `time::Duration`"
448        ))
449    }
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    pub const fn days(days: i64) -> Self {
463        Self::seconds(expect_opt!(
464            days.checked_mul(Second::per(Day) as _),
465            "overflow constructing `time::Duration`"
466        ))
467    }
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    pub const fn hours(hours: i64) -> Self {
481        Self::seconds(expect_opt!(
482            hours.checked_mul(Second::per(Hour) as _),
483            "overflow constructing `time::Duration`"
484        ))
485    }
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    pub const fn minutes(minutes: i64) -> Self {
499        Self::seconds(expect_opt!(
500            minutes.checked_mul(Second::per(Minute) as _),
501            "overflow constructing `time::Duration`"
502        ))
503    }
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    pub const fn seconds(seconds: i64) -> Self {
512        Self::new_ranged_unchecked(seconds, Nanoseconds::new_static::<0>())
513    }
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    pub fn seconds_f64(seconds: f64) -> Self {
523        try_from_secs!(
524            secs = seconds,
525            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            is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f64`"),
533            is_overflow = crate::expect_failed("overflow constructing `time::Duration`"),
534        )
535    }
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    pub fn seconds_f32(seconds: f32) -> Self {
545        try_from_secs!(
546            secs = seconds,
547            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            is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f32`"),
555            is_overflow = crate::expect_failed("overflow constructing `time::Duration`"),
556        )
557    }
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    pub fn saturating_seconds_f64(seconds: f64) -> Self {
582        try_from_secs!(
583            secs = seconds,
584            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            is_nan = return Self::ZERO,
592            is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX },
593        )
594    }
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    pub fn saturating_seconds_f32(seconds: f32) -> Self {
619        try_from_secs!(
620            secs = seconds,
621            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            is_nan = return Self::ZERO,
629            is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX },
630        )
631    }
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    pub fn checked_seconds_f64(seconds: f64) -> Option<Self> {
646        Some(try_from_secs!(
647            secs = seconds,
648            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            is_nan = return None,
656            is_overflow = return None,
657        ))
658    }
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    pub fn checked_seconds_f32(seconds: f32) -> Option<Self> {
673        Some(try_from_secs!(
674            secs = seconds,
675            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            is_nan = return None,
683            is_overflow = return None,
684        ))
685    }
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    pub const fn milliseconds(milliseconds: i64) -> Self {
695        // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
696        unsafe {
697            Self::new_unchecked(
698                milliseconds / Millisecond::per(Second) as i64,
699                (milliseconds % Millisecond::per(Second) as i64
700                    * Nanosecond::per(Millisecond) as i64) as _,
701            )
702        }
703    }
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    pub const fn microseconds(microseconds: i64) -> Self {
713        // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
714        unsafe {
715            Self::new_unchecked(
716                microseconds / Microsecond::per(Second) as i64,
717                (microseconds % Microsecond::per(Second) as i64
718                    * Nanosecond::per(Microsecond) as i64) as _,
719            )
720        }
721    }
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    pub const fn nanoseconds(nanoseconds: i64) -> Self {
731        // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
732        unsafe {
733            Self::new_unchecked(
734                nanoseconds / Nanosecond::per(Second) as i64,
735                (nanoseconds % Nanosecond::per(Second) as i64) as _,
736            )
737        }
738    }
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    pub(crate) const fn nanoseconds_i128(nanoseconds: i128) -> Self {
745        let seconds = nanoseconds / Nanosecond::per(Second) as i128;
746        let nanoseconds = nanoseconds % Nanosecond::per(Second) as i128;
747
748        if seconds > i64::MAX as i128 || seconds < i64::MIN as i128 {
749            crate::expect_failed("overflow constructing `time::Duration`");
750        }
751
752        // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
753        unsafe { Self::new_unchecked(seconds as _, nanoseconds as _) }
754    }
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    pub const fn whole_weeks(self) -> i64 {
768        self.whole_seconds() / Second::per(Week) as i64
769    }
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    pub const fn whole_days(self) -> i64 {
781        self.whole_seconds() / Second::per(Day) as i64
782    }
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    pub const fn whole_hours(self) -> i64 {
794        self.whole_seconds() / Second::per(Hour) as i64
795    }
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    pub const fn whole_minutes(self) -> i64 {
807        self.whole_seconds() / Second::per(Minute) as i64
808    }
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    pub const fn whole_seconds(self) -> i64 {
820        self.seconds
821    }
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    pub fn as_seconds_f64(self) -> f64 {
831        self.seconds as f64 + self.nanoseconds.get() as f64 / Nanosecond::per(Second) as f64
832    }
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    pub fn as_seconds_f32(self) -> f32 {
842        self.seconds as f32 + self.nanoseconds.get() as f32 / Nanosecond::per(Second) as f32
843    }
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    pub const fn whole_milliseconds(self) -> i128 {
855        self.seconds as i128 * Millisecond::per(Second) as i128
856            + self.nanoseconds.get() as i128 / Nanosecond::per(Millisecond) as i128
857    }
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    pub const fn subsec_milliseconds(self) -> i16 {
870        (self.nanoseconds.get() / Nanosecond::per(Millisecond) as i32) as _
871    }
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    pub const fn whole_microseconds(self) -> i128 {
883        self.seconds as i128 * Microsecond::per(Second) as i128
884            + self.nanoseconds.get() as i128 / Nanosecond::per(Microsecond) as i128
885    }
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    pub const fn subsec_microseconds(self) -> i32 {
897        self.nanoseconds.get() / Nanosecond::per(Microsecond) as i32
898    }
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    pub const fn whole_nanoseconds(self) -> i128 {
910        self.seconds as i128 * Nanosecond::per(Second) as i128 + self.nanoseconds.get() as i128
911    }
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    pub const fn subsec_nanoseconds(self) -> i32 {
923        self.nanoseconds.get()
924    }
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    pub const fn checked_add(self, rhs: Self) -> Option<Self> {
943        let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds));
944        let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
945
946        if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
947            nanoseconds -= Nanosecond::per(Second) as i32;
948            seconds = const_try_opt!(seconds.checked_add(1));
949        } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
950        {
951            nanoseconds += Nanosecond::per(Second) as i32;
952            seconds = const_try_opt!(seconds.checked_sub(1));
953        }
954
955        // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
956        unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
957    }
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    pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
968        let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds));
969        let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
970
971        if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
972            nanoseconds -= Nanosecond::per(Second) as i32;
973            seconds = const_try_opt!(seconds.checked_add(1));
974        } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
975        {
976            nanoseconds += Nanosecond::per(Second) as i32;
977            seconds = const_try_opt!(seconds.checked_sub(1));
978        }
979
980        // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
981        unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
982    }
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    pub const fn checked_mul(self, rhs: i32) -> Option<Self> {
995        // Multiply nanoseconds as i64, because it cannot overflow that way.
996        let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
997        let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
998        let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as _;
999        let seconds = const_try_opt!(
1000            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        unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
1005    }
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    pub const fn checked_div(self, rhs: i32) -> Option<Self> {
1016        let (secs, extra_secs) = (
1017            const_try_opt!(self.seconds.checked_div(rhs as i64)),
1018            self.seconds % (rhs as i64),
1019        );
1020        let (mut nanos, extra_nanos) = (self.nanoseconds.get() / rhs, self.nanoseconds.get() % rhs);
1021        nanos += ((extra_secs * (Nanosecond::per(Second) as i64) + extra_nanos as i64)
1022            / (rhs as i64)) as i32;
1023
1024        // Safety: `nanoseconds` is in range.
1025        unsafe { Some(Self::new_unchecked(secs, nanos)) }
1026    }
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    pub const fn checked_neg(self) -> Option<Self> {
1037        if self.seconds == i64::MIN {
1038            None
1039        } else {
1040            Some(Self::new_ranged_unchecked(
1041                -self.seconds,
1042                self.nanoseconds.neg(),
1043            ))
1044        }
1045    }
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    pub const fn saturating_add(self, rhs: Self) -> Self {
1062        let (mut seconds, overflow) = self.seconds.overflowing_add(rhs.seconds);
1063        if overflow {
1064            if self.seconds > 0 {
1065                return Self::MAX;
1066            }
1067            return Self::MIN;
1068        }
1069        let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
1070
1071        if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
1072            nanoseconds -= Nanosecond::per(Second) as i32;
1073            seconds = match seconds.checked_add(1) {
1074                Some(seconds) => seconds,
1075                None => return Self::MAX,
1076            };
1077        } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
1078        {
1079            nanoseconds += Nanosecond::per(Second) as i32;
1080            seconds = match seconds.checked_sub(1) {
1081                Some(seconds) => seconds,
1082                None => return Self::MIN,
1083            };
1084        }
1085
1086        // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
1087        unsafe { Self::new_unchecked(seconds, nanoseconds) }
1088    }
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    pub const fn saturating_sub(self, rhs: Self) -> Self {
1103        let (mut seconds, overflow) = self.seconds.overflowing_sub(rhs.seconds);
1104        if overflow {
1105            if self.seconds > 0 {
1106                return Self::MAX;
1107            }
1108            return Self::MIN;
1109        }
1110        let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
1111
1112        if nanoseconds >= Nanosecond::per(Second) as _ || seconds < 0 && nanoseconds > 0 {
1113            nanoseconds -= Nanosecond::per(Second) as i32;
1114            seconds = match seconds.checked_add(1) {
1115                Some(seconds) => seconds,
1116                None => return Self::MAX,
1117            };
1118        } else if nanoseconds <= -(Nanosecond::per(Second) as i32) || seconds > 0 && nanoseconds < 0
1119        {
1120            nanoseconds += Nanosecond::per(Second) as i32;
1121            seconds = match seconds.checked_sub(1) {
1122                Some(seconds) => seconds,
1123                None => return Self::MIN,
1124            };
1125        }
1126
1127        // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
1128        unsafe { Self::new_unchecked(seconds, nanoseconds) }
1129    }
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    pub const fn saturating_mul(self, rhs: i32) -> Self {
1144        // Multiply nanoseconds as i64, because it cannot overflow that way.
1145        let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
1146        let extra_secs = total_nanos / Nanosecond::per(Second) as i64;
1147        let nanoseconds = (total_nanos % Nanosecond::per(Second) as i64) as _;
1148        let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as _);
1149        if overflow1 {
1150            if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 {
1151                return Self::MAX;
1152            }
1153            return Self::MIN;
1154        }
1155        let (seconds, overflow2) = seconds.overflowing_add(extra_secs);
1156        if overflow2 {
1157            if self.seconds > 0 && rhs > 0 {
1158                return Self::MAX;
1159            }
1160            return Self::MIN;
1161        }
1162
1163        // Safety: `nanoseconds` is guaranteed to be in range because of to the modulus above.
1164        unsafe { Self::new_unchecked(seconds, nanoseconds) }
1165    }
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    pub fn time_fn<T>(f: impl FnOnce() -> T) -> (Self, T) {
1178        let start = Instant::now();
1179        let return_value = f();
1180        let end = Instant::now();
1181
1182        (end - start, return_value)
1183    }
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.
1201impl fmt::Display for Duration {
1202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1203        if self.is_negative() {
1204            f.write_str("-")?;
1205        }
1206
1207        if let Some(_precision) = f.precision() {
1208            // Concise, rounded representation.
1209
1210            if self.is_zero() {
1211                // Write a zero value with the requested precision.
1212                return (0.).fmt(f).and_then(|_| f.write_str("s"));
1213            }
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                        return value.fmt(f).and_then(|_| f.write_str($name));
1221                    }
1222                };
1223            }
1224
1225            // Even if this produces a de-normal float, because we're rounding we don't really care.
1226            let seconds = self.unsigned_abs().as_secs_f64();
1227
1228            item!("d", seconds / Second::per(Day) as f64);
1229            item!("h", seconds / Second::per(Hour) as f64);
1230            item!("m", seconds / Second::per(Minute) as f64);
1231            item!("s", seconds);
1232            item!("ms", seconds * Millisecond::per(Second) as f64);
1233            item!("µs", seconds * Microsecond::per(Second) as f64);
1234            item!("ns", seconds * Nanosecond::per(Second) as f64);
1235        } else {
1236            // Precise, but verbose representation.
1237
1238            if self.is_zero() {
1239                return f.write_str("0s");
1240            }
1241
1242            /// Format a single item.
1243            macro_rules! item {
1244                ($name:literal, $value:expr) => {
1245                    match $value {
1246                        0 => Ok(()),
1247                        value => value.fmt(f).and_then(|_| f.write_str($name)),
1248                    }
1249                };
1250            }
1251
1252            let seconds = self.seconds.unsigned_abs();
1253            let nanoseconds = self.nanoseconds.get().unsigned_abs();
1254
1255            item!("d", seconds / Second::per(Day).extend::<u64>())?;
1256            item!(
1257                "h",
1258                seconds / Second::per(Hour).extend::<u64>() % Hour::per(Day).extend::<u64>()
1259            )?;
1260            item!(
1261                "m",
1262                seconds / Second::per(Minute).extend::<u64>() % Minute::per(Hour).extend::<u64>()
1263            )?;
1264            item!("s", seconds % Second::per(Minute).extend::<u64>())?;
1265            item!("ms", nanoseconds / Nanosecond::per(Millisecond))?;
1266            item!(
1267                "µs",
1268                nanoseconds / Nanosecond::per(Microsecond).extend::<u32>()
1269                    % Microsecond::per(Millisecond).extend::<u32>()
1270            )?;
1271            item!(
1272                "ns",
1273                nanoseconds % Nanosecond::per(Microsecond).extend::<u32>()
1274            )?;
1275        }
1276
1277        Ok(())
1278    }
1279}
1280
1281impl TryFrom<StdDuration> for Duration {
1282    type Error = error::ConversionRange;
1283
1284    fn try_from(original: StdDuration) -> Result<Self, error::ConversionRange> {
1285        Ok(Self::new(
1286            original
1287                .as_secs()
1288                .try_into()
1289                .map_err(|_| error::ConversionRange)?,
1290            original.subsec_nanos().cast_signed(),
1291        ))
1292    }
1293}
1294
1295impl TryFrom<Duration> for StdDuration {
1296    type Error = error::ConversionRange;
1297
1298    fn try_from(duration: Duration) -> Result<Self, error::ConversionRange> {
1299        Ok(Self::new(
1300            duration
1301                .seconds
1302                .try_into()
1303                .map_err(|_| error::ConversionRange)?,
1304            duration
1305                .nanoseconds
1306                .get()
1307                .try_into()
1308                .map_err(|_| error::ConversionRange)?,
1309        ))
1310    }
1311}
1312
1313impl Add for Duration {
1314    type Output = Self;
1315
1316    /// # Panics
1317    ///
1318    /// This may panic if an overflow occurs.
1319    fn add(self, rhs: Self) -> Self::Output {
1320        self.checked_add(rhs)
1321            .expect("overflow when adding durations")
1322    }
1323}
1324
1325impl Add<StdDuration> for Duration {
1326    type Output = Self;
1327
1328    /// # Panics
1329    ///
1330    /// This may panic if an overflow occurs.
1331    fn add(self, std_duration: StdDuration) -> Self::Output {
1332        self + Self::try_from(std_duration)
1333            .expect("overflow converting `std::time::Duration` to `time::Duration`")
1334    }
1335}
1336
1337impl Add<Duration> for StdDuration {
1338    type Output = Duration;
1339
1340    fn add(self, rhs: Duration) -> Self::Output {
1341        rhs + self
1342    }
1343}
1344
1345impl_add_assign!(Duration: Self, StdDuration);
1346
1347impl AddAssign<Duration> for StdDuration {
1348    /// # Panics
1349    ///
1350    /// This may panic if the resulting addition cannot be represented.
1351    fn add_assign(&mut self, rhs: Duration) {
1352        *self = (*self + rhs).try_into().expect(
1353            "Cannot represent a resulting duration in std. Try `let x = x + rhs;`, which will \
1354             change the type.",
1355        );
1356    }
1357}
1358
1359impl Neg for Duration {
1360    type Output = Self;
1361
1362    fn neg(self) -> Self::Output {
1363        self.checked_neg().expect("overflow when negating duration")
1364    }
1365}
1366
1367impl Sub for Duration {
1368    type Output = Self;
1369
1370    /// # Panics
1371    ///
1372    /// This may panic if an overflow occurs.
1373    fn sub(self, rhs: Self) -> Self::Output {
1374        self.checked_sub(rhs)
1375            .expect("overflow when subtracting durations")
1376    }
1377}
1378
1379impl Sub<StdDuration> for Duration {
1380    type Output = Self;
1381
1382    /// # Panics
1383    ///
1384    /// This may panic if an overflow occurs.
1385    fn sub(self, rhs: StdDuration) -> Self::Output {
1386        self - Self::try_from(rhs)
1387            .expect("overflow converting `std::time::Duration` to `time::Duration`")
1388    }
1389}
1390
1391impl Sub<Duration> for StdDuration {
1392    type Output = Duration;
1393
1394    /// # Panics
1395    ///
1396    /// This may panic if an overflow occurs.
1397    fn sub(self, rhs: Duration) -> Self::Output {
1398        Duration::try_from(self)
1399            .expect("overflow converting `std::time::Duration` to `time::Duration`")
1400            - rhs
1401    }
1402}
1403
1404impl_sub_assign!(Duration: Self, StdDuration);
1405
1406impl SubAssign<Duration> for StdDuration {
1407    /// # Panics
1408    ///
1409    /// This may panic if the resulting subtraction can not be represented.
1410    fn sub_assign(&mut self, rhs: Duration) {
1411        *self = (*self - rhs).try_into().expect(
1412            "Cannot represent a resulting duration in std. Try `let x = x - rhs;`, which will \
1413             change the type.",
1414        );
1415    }
1416}
1417
1418/// Implement `Mul` (reflexively) and `Div` for `Duration` for various types.
1419macro_rules! duration_mul_div_int {
1420    ($($type:ty),+) => {$(
1421        impl Mul<$type> for Duration {
1422            type Output = Self;
1423
1424            fn mul(self, rhs: $type) -> Self::Output {
1425                Self::nanoseconds_i128(
1426                    self.whole_nanoseconds()
1427                        .checked_mul(rhs.cast_signed().extend::<i128>())
1428                        .expect("overflow when multiplying duration")
1429                )
1430            }
1431        }
1432
1433        impl Mul<Duration> for $type {
1434            type Output = Duration;
1435
1436            fn mul(self, rhs: Duration) -> Self::Output {
1437                rhs * self
1438            }
1439        }
1440
1441        impl Div<$type> for Duration {
1442            type Output = Self;
1443
1444            fn div(self, rhs: $type) -> Self::Output {
1445                Self::nanoseconds_i128(
1446                    self.whole_nanoseconds() / rhs.cast_signed().extend::<i128>()
1447                )
1448            }
1449        }
1450    )+};
1451}
1452duration_mul_div_int![i8, i16, i32, u8, u16, u32];
1453
1454impl Mul<f32> for Duration {
1455    type Output = Self;
1456
1457    fn mul(self, rhs: f32) -> Self::Output {
1458        Self::seconds_f32(self.as_seconds_f32() * rhs)
1459    }
1460}
1461
1462impl Mul<Duration> for f32 {
1463    type Output = Duration;
1464
1465    fn mul(self, rhs: Duration) -> Self::Output {
1466        rhs * self
1467    }
1468}
1469
1470impl Mul<f64> for Duration {
1471    type Output = Self;
1472
1473    fn mul(self, rhs: f64) -> Self::Output {
1474        Self::seconds_f64(self.as_seconds_f64() * rhs)
1475    }
1476}
1477
1478impl Mul<Duration> for f64 {
1479    type Output = Duration;
1480
1481    fn mul(self, rhs: Duration) -> Self::Output {
1482        rhs * self
1483    }
1484}
1485
1486impl_mul_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
1487
1488impl Div<f32> for Duration {
1489    type Output = Self;
1490
1491    fn div(self, rhs: f32) -> Self::Output {
1492        Self::seconds_f32(self.as_seconds_f32() / rhs)
1493    }
1494}
1495
1496impl Div<f64> for Duration {
1497    type Output = Self;
1498
1499    fn div(self, rhs: f64) -> Self::Output {
1500        Self::seconds_f64(self.as_seconds_f64() / rhs)
1501    }
1502}
1503
1504impl_div_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
1505
1506impl Div for Duration {
1507    type Output = f64;
1508
1509    fn div(self, rhs: Self) -> Self::Output {
1510        self.as_seconds_f64() / rhs.as_seconds_f64()
1511    }
1512}
1513
1514impl Div<StdDuration> for Duration {
1515    type Output = f64;
1516
1517    fn div(self, rhs: StdDuration) -> Self::Output {
1518        self.as_seconds_f64() / rhs.as_secs_f64()
1519    }
1520}
1521
1522impl Div<Duration> for StdDuration {
1523    type Output = f64;
1524
1525    fn div(self, rhs: Duration) -> Self::Output {
1526        self.as_secs_f64() / rhs.as_seconds_f64()
1527    }
1528}
1529
1530impl PartialEq<StdDuration> for Duration {
1531    fn eq(&self, rhs: &StdDuration) -> bool {
1532        Ok(*self) == Self::try_from(*rhs)
1533    }
1534}
1535
1536impl PartialEq<Duration> for StdDuration {
1537    fn eq(&self, rhs: &Duration) -> bool {
1538        rhs == self
1539    }
1540}
1541
1542impl PartialOrd<StdDuration> for Duration {
1543    fn partial_cmp(&self, rhs: &StdDuration) -> Option<Ordering> {
1544        if rhs.as_secs() > i64::MAX.cast_unsigned() {
1545            return Some(Ordering::Less);
1546        }
1547
1548        Some(
1549            self.seconds
1550                .cmp(&rhs.as_secs().cast_signed())
1551                .then_with(|| {
1552                    self.nanoseconds
1553                        .get()
1554                        .cmp(&rhs.subsec_nanos().cast_signed())
1555                }),
1556        )
1557    }
1558}
1559
1560impl PartialOrd<Duration> for StdDuration {
1561    fn partial_cmp(&self, rhs: &Duration) -> Option<Ordering> {
1562        rhs.partial_cmp(self).map(Ordering::reverse)
1563    }
1564}
1565
1566impl Sum for Duration {
1567    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1568        iter.reduce(|a, b| a + b).unwrap_or_default()
1569    }
1570}
1571
1572impl<'a> Sum<&'a Self> for Duration {
1573    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
1574        iter.copied().sum()
1575    }
1576}
1577// endregion trait impls