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