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