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