chrono/
time_delta.rs

1// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Temporal quantification
12
13use core::fmt;
14use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
15use core::time::Duration;
16#[cfg(feature = "std")]
17use std::error::Error;
18
19use crate::{expect, try_opt};
20
21#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
22use rkyv::{Archive, Deserialize, Serialize};
23
24/// The number of nanoseconds in a microsecond.
25const NANOS_PER_MICRO: i32 = 1000;
26/// The number of nanoseconds in a millisecond.
27const NANOS_PER_MILLI: i32 = 1_000_000;
28/// The number of nanoseconds in seconds.
29pub(crate) const NANOS_PER_SEC: i32 = 1_000_000_000;
30/// The number of microseconds per second.
31const MICROS_PER_SEC: i64 = 1_000_000;
32/// The number of milliseconds per second.
33const MILLIS_PER_SEC: i64 = 1000;
34/// The number of seconds in a minute.
35const SECS_PER_MINUTE: i64 = 60;
36/// The number of seconds in an hour.
37const SECS_PER_HOUR: i64 = 3600;
38/// The number of (non-leap) seconds in days.
39const SECS_PER_DAY: i64 = 86_400;
40/// The number of (non-leap) seconds in a week.
41const SECS_PER_WEEK: i64 = 604_800;
42
43/// Time duration with nanosecond precision.
44///
45/// This also allows for negative durations; see individual methods for details.
46///
47/// A `TimeDelta` is represented internally as a complement of seconds and
48/// nanoseconds. The range is restricted to that of `i64` milliseconds, with the
49/// minimum value notably being set to `-i64::MAX` rather than allowing the full
50/// range of `i64::MIN`. This is to allow easy flipping of sign, so that for
51/// instance `abs()` can be called without any checks.
52#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
53#[cfg_attr(
54    any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
55    derive(Archive, Deserialize, Serialize),
56    archive(compare(PartialEq, PartialOrd)),
57    archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
58)]
59#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
60pub struct TimeDelta {
61    secs: i64,
62    nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
63}
64
65/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
66pub(crate) const MIN: TimeDelta = TimeDelta {
67    secs: -i64::MAX / MILLIS_PER_SEC - 1,
68    nanos: NANOS_PER_SEC + (-i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
69};
70
71/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
72pub(crate) const MAX: TimeDelta = TimeDelta {
73    secs: i64::MAX / MILLIS_PER_SEC,
74    nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
75};
76
77impl TimeDelta {
78    /// Makes a new `TimeDelta` with given number of seconds and nanoseconds.
79    ///
80    /// # Errors
81    ///
82    /// Returns `None` when the duration is out of bounds, or if `nanos` ≥ 1,000,000,000.
83    pub const fn new(secs: i64, nanos: u32) -> Option<TimeDelta> {
84        if secs < MIN.secs
85            || secs > MAX.secs
86            || nanos >= 1_000_000_000
87            || (secs == MAX.secs && nanos > MAX.nanos as u32)
88            || (secs == MIN.secs && nanos < MIN.nanos as u32)
89        {
90            return None;
91        }
92        Some(TimeDelta { secs, nanos: nanos as i32 })
93    }
94
95    /// Makes a new `TimeDelta` with the given number of weeks.
96    ///
97    /// Equivalent to `TimeDelta::seconds(weeks * 7 * 24 * 60 * 60)` with
98    /// overflow checks.
99    ///
100    /// # Panics
101    ///
102    /// Panics when the duration is out of bounds.
103    #[inline]
104    #[must_use]
105    pub const fn weeks(weeks: i64) -> TimeDelta {
106        expect(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds")
107    }
108
109    /// Makes a new `TimeDelta` with the given number of weeks.
110    ///
111    /// Equivalent to `TimeDelta::try_seconds(weeks * 7 * 24 * 60 * 60)` with
112    /// overflow checks.
113    ///
114    /// # Errors
115    ///
116    /// Returns `None` when the `TimeDelta` would be out of bounds.
117    #[inline]
118    pub const fn try_weeks(weeks: i64) -> Option<TimeDelta> {
119        TimeDelta::try_seconds(try_opt!(weeks.checked_mul(SECS_PER_WEEK)))
120    }
121
122    /// Makes a new `TimeDelta` with the given number of days.
123    ///
124    /// Equivalent to `TimeDelta::seconds(days * 24 * 60 * 60)` with overflow
125    /// checks.
126    ///
127    /// # Panics
128    ///
129    /// Panics when the `TimeDelta` would be out of bounds.
130    #[inline]
131    #[must_use]
132    pub const fn days(days: i64) -> TimeDelta {
133        expect(TimeDelta::try_days(days), "TimeDelta::days out of bounds")
134    }
135
136    /// Makes a new `TimeDelta` with the given number of days.
137    ///
138    /// Equivalent to `TimeDelta::try_seconds(days * 24 * 60 * 60)` with overflow
139    /// checks.
140    ///
141    /// # Errors
142    ///
143    /// Returns `None` when the `TimeDelta` would be out of bounds.
144    #[inline]
145    pub const fn try_days(days: i64) -> Option<TimeDelta> {
146        TimeDelta::try_seconds(try_opt!(days.checked_mul(SECS_PER_DAY)))
147    }
148
149    /// Makes a new `TimeDelta` with the given number of hours.
150    ///
151    /// Equivalent to `TimeDelta::seconds(hours * 60 * 60)` with overflow checks.
152    ///
153    /// # Panics
154    ///
155    /// Panics when the `TimeDelta` would be out of bounds.
156    #[inline]
157    #[must_use]
158    pub const fn hours(hours: i64) -> TimeDelta {
159        expect(TimeDelta::try_hours(hours), "TimeDelta::hours out of bounds")
160    }
161
162    /// Makes a new `TimeDelta` with the given number of hours.
163    ///
164    /// Equivalent to `TimeDelta::try_seconds(hours * 60 * 60)` with overflow checks.
165    ///
166    /// # Errors
167    ///
168    /// Returns `None` when the `TimeDelta` would be out of bounds.
169    #[inline]
170    pub const fn try_hours(hours: i64) -> Option<TimeDelta> {
171        TimeDelta::try_seconds(try_opt!(hours.checked_mul(SECS_PER_HOUR)))
172    }
173
174    /// Makes a new `TimeDelta` with the given number of minutes.
175    ///
176    /// Equivalent to `TimeDelta::seconds(minutes * 60)` with overflow checks.
177    ///
178    /// # Panics
179    ///
180    /// Panics when the `TimeDelta` would be out of bounds.
181    #[inline]
182    #[must_use]
183    pub const fn minutes(minutes: i64) -> TimeDelta {
184        expect(TimeDelta::try_minutes(minutes), "TimeDelta::minutes out of bounds")
185    }
186
187    /// Makes a new `TimeDelta` with the given number of minutes.
188    ///
189    /// Equivalent to `TimeDelta::try_seconds(minutes * 60)` with overflow checks.
190    ///
191    /// # Errors
192    ///
193    /// Returns `None` when the `TimeDelta` would be out of bounds.
194    #[inline]
195    pub const fn try_minutes(minutes: i64) -> Option<TimeDelta> {
196        TimeDelta::try_seconds(try_opt!(minutes.checked_mul(SECS_PER_MINUTE)))
197    }
198
199    /// Makes a new `TimeDelta` with the given number of seconds.
200    ///
201    /// # Panics
202    ///
203    /// Panics when `seconds` is more than `i64::MAX / 1_000` or less than `-i64::MAX / 1_000`
204    /// (in this context, this is the same as `i64::MIN / 1_000` due to rounding).
205    #[inline]
206    #[must_use]
207    pub const fn seconds(seconds: i64) -> TimeDelta {
208        expect(TimeDelta::try_seconds(seconds), "TimeDelta::seconds out of bounds")
209    }
210
211    /// Makes a new `TimeDelta` with the given number of seconds.
212    ///
213    /// # Errors
214    ///
215    /// Returns `None` when `seconds` is more than `i64::MAX / 1_000` or less than
216    /// `-i64::MAX / 1_000` (in this context, this is the same as `i64::MIN / 1_000` due to
217    /// rounding).
218    #[inline]
219    pub const fn try_seconds(seconds: i64) -> Option<TimeDelta> {
220        TimeDelta::new(seconds, 0)
221    }
222
223    /// Makes a new `TimeDelta` with the given number of milliseconds.
224    ///
225    /// # Panics
226    ///
227    /// Panics when the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more than
228    /// `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
229    #[inline]
230    pub const fn milliseconds(milliseconds: i64) -> TimeDelta {
231        expect(TimeDelta::try_milliseconds(milliseconds), "TimeDelta::milliseconds out of bounds")
232    }
233
234    /// Makes a new `TimeDelta` with the given number of milliseconds.
235    ///
236    /// # Errors
237    ///
238    /// Returns `None` the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more
239    /// than `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
240    #[inline]
241    pub const fn try_milliseconds(milliseconds: i64) -> Option<TimeDelta> {
242        // We don't need to compare against MAX, as this function accepts an
243        // i64, and MAX is aligned to i64::MAX milliseconds.
244        if milliseconds < -i64::MAX {
245            return None;
246        }
247        let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
248        let d = TimeDelta { secs, nanos: millis as i32 * NANOS_PER_MILLI };
249        Some(d)
250    }
251
252    /// Makes a new `TimeDelta` with the given number of microseconds.
253    ///
254    /// The number of microseconds acceptable by this constructor is less than
255    /// the total number that can actually be stored in a `TimeDelta`, so it is
256    /// not possible to specify a value that would be out of bounds. This
257    /// function is therefore infallible.
258    #[inline]
259    pub const fn microseconds(microseconds: i64) -> TimeDelta {
260        let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
261        let nanos = micros as i32 * NANOS_PER_MICRO;
262        TimeDelta { secs, nanos }
263    }
264
265    /// Makes a new `TimeDelta` with the given number of nanoseconds.
266    ///
267    /// The number of nanoseconds acceptable by this constructor is less than
268    /// the total number that can actually be stored in a `TimeDelta`, so it is
269    /// not possible to specify a value that would be out of bounds. This
270    /// function is therefore infallible.
271    #[inline]
272    pub const fn nanoseconds(nanos: i64) -> TimeDelta {
273        let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64);
274        TimeDelta { secs, nanos: nanos as i32 }
275    }
276
277    /// Returns the total number of whole weeks in the `TimeDelta`.
278    #[inline]
279    pub const fn num_weeks(&self) -> i64 {
280        self.num_days() / 7
281    }
282
283    /// Returns the total number of whole days in the `TimeDelta`.
284    #[inline]
285    pub const fn num_days(&self) -> i64 {
286        self.num_seconds() / SECS_PER_DAY
287    }
288
289    /// Returns the total number of whole hours in the `TimeDelta`.
290    #[inline]
291    pub const fn num_hours(&self) -> i64 {
292        self.num_seconds() / SECS_PER_HOUR
293    }
294
295    /// Returns the total number of whole minutes in the `TimeDelta`.
296    #[inline]
297    pub const fn num_minutes(&self) -> i64 {
298        self.num_seconds() / SECS_PER_MINUTE
299    }
300
301    /// Returns the total number of whole seconds in the `TimeDelta`.
302    pub const fn num_seconds(&self) -> i64 {
303        // If secs is negative, nanos should be subtracted from the duration.
304        if self.secs < 0 && self.nanos > 0 { self.secs + 1 } else { self.secs }
305    }
306
307    /// Returns the number of nanoseconds such that
308    /// `subsec_nanos() + num_seconds() * NANOS_PER_SEC` is the total number of
309    /// nanoseconds in the `TimeDelta`.
310    pub const fn subsec_nanos(&self) -> i32 {
311        if self.secs < 0 && self.nanos > 0 { self.nanos - NANOS_PER_SEC } else { self.nanos }
312    }
313
314    /// Returns the total number of whole milliseconds in the `TimeDelta`.
315    pub const fn num_milliseconds(&self) -> i64 {
316        // A proper TimeDelta will not overflow, because MIN and MAX are defined such
317        // that the range is within the bounds of an i64, from -i64::MAX through to
318        // +i64::MAX inclusive. Notably, i64::MIN is excluded from this range.
319        let secs_part = self.num_seconds() * MILLIS_PER_SEC;
320        let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI;
321        secs_part + nanos_part as i64
322    }
323
324    /// Returns the total number of whole microseconds in the `TimeDelta`,
325    /// or `None` on overflow (exceeding 2^63 microseconds in either direction).
326    pub const fn num_microseconds(&self) -> Option<i64> {
327        let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
328        let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO;
329        secs_part.checked_add(nanos_part as i64)
330    }
331
332    /// Returns the total number of whole nanoseconds in the `TimeDelta`,
333    /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
334    pub const fn num_nanoseconds(&self) -> Option<i64> {
335        let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
336        let nanos_part = self.subsec_nanos();
337        secs_part.checked_add(nanos_part as i64)
338    }
339
340    /// Add two `TimeDelta`s, returning `None` if overflow occurred.
341    #[must_use]
342    pub const fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
343        // No overflow checks here because we stay comfortably within the range of an `i64`.
344        // Range checks happen in `TimeDelta::new`.
345        let mut secs = self.secs + rhs.secs;
346        let mut nanos = self.nanos + rhs.nanos;
347        if nanos >= NANOS_PER_SEC {
348            nanos -= NANOS_PER_SEC;
349            secs += 1;
350        }
351        TimeDelta::new(secs, nanos as u32)
352    }
353
354    /// Subtract two `TimeDelta`s, returning `None` if overflow occurred.
355    #[must_use]
356    pub const fn checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
357        // No overflow checks here because we stay comfortably within the range of an `i64`.
358        // Range checks happen in `TimeDelta::new`.
359        let mut secs = self.secs - rhs.secs;
360        let mut nanos = self.nanos - rhs.nanos;
361        if nanos < 0 {
362            nanos += NANOS_PER_SEC;
363            secs -= 1;
364        }
365        TimeDelta::new(secs, nanos as u32)
366    }
367
368    /// Multiply a `TimeDelta` with a i32, returning `None` if overflow occurred.
369    #[must_use]
370    pub const fn checked_mul(&self, rhs: i32) -> Option<TimeDelta> {
371        // Multiply nanoseconds as i64, because it cannot overflow that way.
372        let total_nanos = self.nanos as i64 * rhs as i64;
373        let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
374        // Multiply seconds as i128 to prevent overflow
375        let secs: i128 = self.secs as i128 * rhs as i128 + extra_secs as i128;
376        if secs <= i64::MIN as i128 || secs >= i64::MAX as i128 {
377            return None;
378        };
379        Some(TimeDelta { secs: secs as i64, nanos: nanos as i32 })
380    }
381
382    /// Divide a `TimeDelta` with a i32, returning `None` if dividing by 0.
383    #[must_use]
384    pub const fn checked_div(&self, rhs: i32) -> Option<TimeDelta> {
385        if rhs == 0 {
386            return None;
387        }
388        let secs = self.secs / rhs as i64;
389        let carry = self.secs % rhs as i64;
390        let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64;
391        let nanos = self.nanos / rhs + extra_nanos as i32;
392
393        let (secs, nanos) = match nanos {
394            i32::MIN..=-1 => (secs - 1, nanos + NANOS_PER_SEC),
395            NANOS_PER_SEC..=i32::MAX => (secs + 1, nanos - NANOS_PER_SEC),
396            _ => (secs, nanos),
397        };
398
399        Some(TimeDelta { secs, nanos })
400    }
401
402    /// Returns the `TimeDelta` as an absolute (non-negative) value.
403    #[inline]
404    pub const fn abs(&self) -> TimeDelta {
405        if self.secs < 0 && self.nanos != 0 {
406            TimeDelta { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos }
407        } else {
408            TimeDelta { secs: self.secs.abs(), nanos: self.nanos }
409        }
410    }
411
412    /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
413    #[deprecated(since = "0.4.39", note = "Use `TimeDelta::MIN` instead")]
414    #[inline]
415    pub const fn min_value() -> TimeDelta {
416        MIN
417    }
418
419    /// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
420    #[deprecated(since = "0.4.39", note = "Use `TimeDelta::MAX` instead")]
421    #[inline]
422    pub const fn max_value() -> TimeDelta {
423        MAX
424    }
425
426    /// A `TimeDelta` where the stored seconds and nanoseconds are equal to zero.
427    #[inline]
428    pub const fn zero() -> TimeDelta {
429        TimeDelta { secs: 0, nanos: 0 }
430    }
431
432    /// Returns `true` if the `TimeDelta` equals `TimeDelta::zero()`.
433    #[inline]
434    pub const fn is_zero(&self) -> bool {
435        self.secs == 0 && self.nanos == 0
436    }
437
438    /// Creates a `TimeDelta` object from `std::time::Duration`
439    ///
440    /// This function errors when original duration is larger than the maximum
441    /// value supported for this type.
442    pub const fn from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError> {
443        // We need to check secs as u64 before coercing to i64
444        if duration.as_secs() > MAX.secs as u64 {
445            return Err(OutOfRangeError(()));
446        }
447        match TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos()) {
448            Some(d) => Ok(d),
449            None => Err(OutOfRangeError(())),
450        }
451    }
452
453    /// Creates a `std::time::Duration` object from a `TimeDelta`.
454    ///
455    /// This function errors when duration is less than zero. As standard
456    /// library implementation is limited to non-negative values.
457    pub const fn to_std(&self) -> Result<Duration, OutOfRangeError> {
458        if self.secs < 0 {
459            return Err(OutOfRangeError(()));
460        }
461        Ok(Duration::new(self.secs as u64, self.nanos as u32))
462    }
463
464    /// This duplicates `Neg::neg` because trait methods can't be const yet.
465    pub(crate) const fn neg(self) -> TimeDelta {
466        let (secs_diff, nanos) = match self.nanos {
467            0 => (0, 0),
468            nanos => (1, NANOS_PER_SEC - nanos),
469        };
470        TimeDelta { secs: -self.secs - secs_diff, nanos }
471    }
472
473    /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
474    pub const MIN: Self = MIN;
475
476    /// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
477    pub const MAX: Self = MAX;
478}
479
480impl Neg for TimeDelta {
481    type Output = TimeDelta;
482
483    #[inline]
484    fn neg(self) -> TimeDelta {
485        let (secs_diff, nanos) = match self.nanos {
486            0 => (0, 0),
487            nanos => (1, NANOS_PER_SEC - nanos),
488        };
489        TimeDelta { secs: -self.secs - secs_diff, nanos }
490    }
491}
492
493impl Add for TimeDelta {
494    type Output = TimeDelta;
495
496    fn add(self, rhs: TimeDelta) -> TimeDelta {
497        self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed")
498    }
499}
500
501impl Sub for TimeDelta {
502    type Output = TimeDelta;
503
504    fn sub(self, rhs: TimeDelta) -> TimeDelta {
505        self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed")
506    }
507}
508
509impl AddAssign for TimeDelta {
510    fn add_assign(&mut self, rhs: TimeDelta) {
511        let new = self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed");
512        *self = new;
513    }
514}
515
516impl SubAssign for TimeDelta {
517    fn sub_assign(&mut self, rhs: TimeDelta) {
518        let new = self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed");
519        *self = new;
520    }
521}
522
523impl Mul<i32> for TimeDelta {
524    type Output = TimeDelta;
525
526    fn mul(self, rhs: i32) -> TimeDelta {
527        self.checked_mul(rhs).expect("`TimeDelta * i32` overflowed")
528    }
529}
530
531impl Div<i32> for TimeDelta {
532    type Output = TimeDelta;
533
534    fn div(self, rhs: i32) -> TimeDelta {
535        self.checked_div(rhs).expect("`i32` is zero")
536    }
537}
538
539impl<'a> core::iter::Sum<&'a TimeDelta> for TimeDelta {
540    fn sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta {
541        iter.fold(TimeDelta::zero(), |acc, x| acc + *x)
542    }
543}
544
545impl core::iter::Sum<TimeDelta> for TimeDelta {
546    fn sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta {
547        iter.fold(TimeDelta::zero(), |acc, x| acc + x)
548    }
549}
550
551impl fmt::Display for TimeDelta {
552    /// Format a `TimeDelta` using the [ISO 8601] format
553    ///
554    /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601#Durations
555    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
556        // technically speaking, negative duration is not valid ISO 8601,
557        // but we need to print it anyway.
558        let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
559
560        write!(f, "{}P", sign)?;
561        // Plenty of ways to encode an empty string. `P0D` is short and not too strange.
562        if abs.secs == 0 && abs.nanos == 0 {
563            return f.write_str("0D");
564        }
565
566        f.write_fmt(format_args!("T{}", abs.secs))?;
567
568        if abs.nanos > 0 {
569            // Count the number of significant digits, while removing all trailing zero's.
570            let mut figures = 9usize;
571            let mut fraction_digits = abs.nanos;
572            loop {
573                let div = fraction_digits / 10;
574                let last_digit = fraction_digits % 10;
575                if last_digit != 0 {
576                    break;
577                }
578                fraction_digits = div;
579                figures -= 1;
580            }
581            f.write_fmt(format_args!(".{:01$}", fraction_digits, figures))?;
582        }
583        f.write_str("S")?;
584        Ok(())
585    }
586}
587
588/// Represents error when converting `TimeDelta` to/from a standard library
589/// implementation
590///
591/// The `std::time::Duration` supports a range from zero to `u64::MAX`
592/// *seconds*, while this module supports signed range of up to
593/// `i64::MAX` of *milliseconds*.
594#[derive(Debug, Clone, Copy, PartialEq, Eq)]
595pub struct OutOfRangeError(());
596
597impl fmt::Display for OutOfRangeError {
598    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
599        write!(f, "Source duration value is out of range for the target type")
600    }
601}
602
603#[cfg(feature = "std")]
604impl Error for OutOfRangeError {
605    #[allow(deprecated)]
606    fn description(&self) -> &str {
607        "out of range error"
608    }
609}
610
611#[inline]
612const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
613    (this.div_euclid(other), this.rem_euclid(other))
614}
615
616#[cfg(all(feature = "arbitrary", feature = "std"))]
617impl arbitrary::Arbitrary<'_> for TimeDelta {
618    fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta> {
619        const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1;
620        const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
621
622        let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
623        let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?;
624        let duration = TimeDelta { secs, nanos };
625
626        if duration < MIN || duration > MAX {
627            Err(arbitrary::Error::IncorrectFormat)
628        } else {
629            Ok(duration)
630        }
631    }
632}
633
634#[cfg(feature = "serde")]
635mod serde {
636    use super::TimeDelta;
637    use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
638
639    impl Serialize for TimeDelta {
640        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
641            <(i64, i32) as Serialize>::serialize(&(self.secs, self.nanos), serializer)
642        }
643    }
644
645    impl<'de> Deserialize<'de> for TimeDelta {
646        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
647            let (secs, nanos) = <(i64, i32) as Deserialize>::deserialize(deserializer)?;
648            TimeDelta::new(secs, nanos as u32).ok_or(Error::custom("TimeDelta out of bounds"))
649        }
650    }
651
652    #[cfg(test)]
653    mod tests {
654        use super::{super::MAX, TimeDelta};
655
656        #[test]
657        fn test_serde() {
658            let duration = TimeDelta::new(123, 456).unwrap();
659            assert_eq!(
660                serde_json::from_value::<TimeDelta>(serde_json::to_value(duration).unwrap())
661                    .unwrap(),
662                duration
663            );
664        }
665
666        #[test]
667        #[should_panic(expected = "TimeDelta out of bounds")]
668        fn test_serde_oob_panic() {
669            let _ =
670                serde_json::from_value::<TimeDelta>(serde_json::json!([MAX.secs + 1, 0])).unwrap();
671        }
672    }
673}
674
675#[cfg(test)]
676mod tests {
677    use super::OutOfRangeError;
678    use super::{MAX, MIN, TimeDelta};
679    use crate::expect;
680    use core::time::Duration;
681
682    #[test]
683    fn test_duration() {
684        let days = |d| TimeDelta::try_days(d).unwrap();
685        let seconds = |s| TimeDelta::try_seconds(s).unwrap();
686
687        assert!(seconds(1) != TimeDelta::zero());
688        assert_eq!(seconds(1) + seconds(2), seconds(3));
689        assert_eq!(seconds(86_399) + seconds(4), days(1) + seconds(3));
690        assert_eq!(days(10) - seconds(1000), seconds(863_000));
691        assert_eq!(days(10) - seconds(1_000_000), seconds(-136_000));
692        assert_eq!(
693            days(2) + seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
694            days(3) + TimeDelta::nanoseconds(234_567_890)
695        );
696        assert_eq!(-days(3), days(-3));
697        assert_eq!(-(days(3) + seconds(70)), days(-4) + seconds(86_400 - 70));
698
699        let mut d = TimeDelta::default();
700        d += TimeDelta::try_minutes(1).unwrap();
701        d -= seconds(30);
702        assert_eq!(d, seconds(30));
703    }
704
705    #[test]
706    fn test_duration_num_days() {
707        assert_eq!(TimeDelta::zero().num_days(), 0);
708        assert_eq!(TimeDelta::try_days(1).unwrap().num_days(), 1);
709        assert_eq!(TimeDelta::try_days(-1).unwrap().num_days(), -1);
710        assert_eq!(TimeDelta::try_seconds(86_399).unwrap().num_days(), 0);
711        assert_eq!(TimeDelta::try_seconds(86_401).unwrap().num_days(), 1);
712        assert_eq!(TimeDelta::try_seconds(-86_399).unwrap().num_days(), 0);
713        assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().num_days(), -1);
714        assert_eq!(TimeDelta::try_days(i32::MAX as i64).unwrap().num_days(), i32::MAX as i64);
715        assert_eq!(TimeDelta::try_days(i32::MIN as i64).unwrap().num_days(), i32::MIN as i64);
716    }
717
718    #[test]
719    fn test_duration_num_seconds() {
720        assert_eq!(TimeDelta::zero().num_seconds(), 0);
721        assert_eq!(TimeDelta::try_seconds(1).unwrap().num_seconds(), 1);
722        assert_eq!(TimeDelta::try_seconds(-1).unwrap().num_seconds(), -1);
723        assert_eq!(TimeDelta::try_milliseconds(999).unwrap().num_seconds(), 0);
724        assert_eq!(TimeDelta::try_milliseconds(1001).unwrap().num_seconds(), 1);
725        assert_eq!(TimeDelta::try_milliseconds(-999).unwrap().num_seconds(), 0);
726        assert_eq!(TimeDelta::try_milliseconds(-1001).unwrap().num_seconds(), -1);
727    }
728
729    #[test]
730    fn test_duration_seconds_max_allowed() {
731        let duration = TimeDelta::try_seconds(i64::MAX / 1_000).unwrap();
732        assert_eq!(duration.num_seconds(), i64::MAX / 1_000);
733        assert_eq!(
734            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
735            i64::MAX as i128 / 1_000 * 1_000_000_000
736        );
737    }
738
739    #[test]
740    fn test_duration_seconds_max_overflow() {
741        assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none());
742    }
743
744    #[test]
745    #[should_panic(expected = "TimeDelta::seconds out of bounds")]
746    fn test_duration_seconds_max_overflow_panic() {
747        let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
748    }
749
750    #[test]
751    fn test_duration_seconds_min_allowed() {
752        let duration = TimeDelta::try_seconds(i64::MIN / 1_000).unwrap(); // Same as -i64::MAX / 1_000 due to rounding
753        assert_eq!(duration.num_seconds(), i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding
754        assert_eq!(
755            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
756            -i64::MAX as i128 / 1_000 * 1_000_000_000
757        );
758    }
759
760    #[test]
761    fn test_duration_seconds_min_underflow() {
762        assert!(TimeDelta::try_seconds(-i64::MAX / 1_000 - 1).is_none());
763    }
764
765    #[test]
766    #[should_panic(expected = "TimeDelta::seconds out of bounds")]
767    fn test_duration_seconds_min_underflow_panic() {
768        let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1);
769    }
770
771    #[test]
772    fn test_duration_num_milliseconds() {
773        assert_eq!(TimeDelta::zero().num_milliseconds(), 0);
774        assert_eq!(TimeDelta::try_milliseconds(1).unwrap().num_milliseconds(), 1);
775        assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().num_milliseconds(), -1);
776        assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0);
777        assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1);
778        assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0);
779        assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1);
780    }
781
782    #[test]
783    fn test_duration_milliseconds_max_allowed() {
784        // The maximum number of milliseconds acceptable through the constructor is
785        // equal to the number that can be stored in a TimeDelta.
786        let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
787        assert_eq!(duration.num_milliseconds(), i64::MAX);
788        assert_eq!(
789            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
790            i64::MAX as i128 * 1_000_000
791        );
792    }
793
794    #[test]
795    fn test_duration_milliseconds_max_overflow() {
796        // Here we ensure that trying to add one millisecond to the maximum storable
797        // value will fail.
798        assert!(
799            TimeDelta::try_milliseconds(i64::MAX)
800                .unwrap()
801                .checked_add(&TimeDelta::try_milliseconds(1).unwrap())
802                .is_none()
803        );
804    }
805
806    #[test]
807    fn test_duration_milliseconds_min_allowed() {
808        // The minimum number of milliseconds acceptable through the constructor is
809        // not equal to the number that can be stored in a TimeDelta - there is a
810        // difference of one (i64::MIN vs -i64::MAX).
811        let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
812        assert_eq!(duration.num_milliseconds(), -i64::MAX);
813        assert_eq!(
814            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
815            -i64::MAX as i128 * 1_000_000
816        );
817    }
818
819    #[test]
820    fn test_duration_milliseconds_min_underflow() {
821        // Here we ensure that trying to subtract one millisecond from the minimum
822        // storable value will fail.
823        assert!(
824            TimeDelta::try_milliseconds(-i64::MAX)
825                .unwrap()
826                .checked_sub(&TimeDelta::try_milliseconds(1).unwrap())
827                .is_none()
828        );
829    }
830
831    #[test]
832    #[should_panic(expected = "TimeDelta::milliseconds out of bounds")]
833    fn test_duration_milliseconds_min_underflow_panic() {
834        // Here we ensure that trying to create a value one millisecond below the
835        // minimum storable value will fail. This test is necessary because the
836        // storable range is -i64::MAX, but the constructor type of i64 will allow
837        // i64::MIN, which is one value below.
838        let _ = TimeDelta::milliseconds(i64::MIN); // Same as -i64::MAX - 1
839    }
840
841    #[test]
842    fn test_duration_num_microseconds() {
843        assert_eq!(TimeDelta::zero().num_microseconds(), Some(0));
844        assert_eq!(TimeDelta::microseconds(1).num_microseconds(), Some(1));
845        assert_eq!(TimeDelta::microseconds(-1).num_microseconds(), Some(-1));
846        assert_eq!(TimeDelta::nanoseconds(999).num_microseconds(), Some(0));
847        assert_eq!(TimeDelta::nanoseconds(1001).num_microseconds(), Some(1));
848        assert_eq!(TimeDelta::nanoseconds(-999).num_microseconds(), Some(0));
849        assert_eq!(TimeDelta::nanoseconds(-1001).num_microseconds(), Some(-1));
850
851        // overflow checks
852        const MICROS_PER_DAY: i64 = 86_400_000_000;
853        assert_eq!(
854            TimeDelta::try_days(i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
855            Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
856        );
857        assert_eq!(
858            TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
859            Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
860        );
861        assert_eq!(
862            TimeDelta::try_days(i64::MAX / MICROS_PER_DAY + 1).unwrap().num_microseconds(),
863            None
864        );
865        assert_eq!(
866            TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY - 1).unwrap().num_microseconds(),
867            None
868        );
869    }
870    #[test]
871    fn test_duration_microseconds_max_allowed() {
872        // The number of microseconds acceptable through the constructor is far
873        // fewer than the number that can actually be stored in a TimeDelta, so this
874        // is not a particular insightful test.
875        let duration = TimeDelta::microseconds(i64::MAX);
876        assert_eq!(duration.num_microseconds(), Some(i64::MAX));
877        assert_eq!(
878            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
879            i64::MAX as i128 * 1_000
880        );
881        // Here we create a TimeDelta with the maximum possible number of
882        // microseconds by creating a TimeDelta with the maximum number of
883        // milliseconds and then checking that the number of microseconds matches
884        // the storage limit.
885        let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
886        assert!(duration.num_microseconds().is_none());
887        assert_eq!(
888            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
889            i64::MAX as i128 * 1_000_000
890        );
891    }
892    #[test]
893    fn test_duration_microseconds_max_overflow() {
894        // This test establishes that a TimeDelta can store more microseconds than
895        // are representable through the return of duration.num_microseconds().
896        let duration = TimeDelta::microseconds(i64::MAX) + TimeDelta::microseconds(1);
897        assert!(duration.num_microseconds().is_none());
898        assert_eq!(
899            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
900            (i64::MAX as i128 + 1) * 1_000
901        );
902        // Here we ensure that trying to add one microsecond to the maximum storable
903        // value will fail.
904        assert!(
905            TimeDelta::try_milliseconds(i64::MAX)
906                .unwrap()
907                .checked_add(&TimeDelta::microseconds(1))
908                .is_none()
909        );
910    }
911    #[test]
912    fn test_duration_microseconds_min_allowed() {
913        // The number of microseconds acceptable through the constructor is far
914        // fewer than the number that can actually be stored in a TimeDelta, so this
915        // is not a particular insightful test.
916        let duration = TimeDelta::microseconds(i64::MIN);
917        assert_eq!(duration.num_microseconds(), Some(i64::MIN));
918        assert_eq!(
919            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
920            i64::MIN as i128 * 1_000
921        );
922        // Here we create a TimeDelta with the minimum possible number of
923        // microseconds by creating a TimeDelta with the minimum number of
924        // milliseconds and then checking that the number of microseconds matches
925        // the storage limit.
926        let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
927        assert!(duration.num_microseconds().is_none());
928        assert_eq!(
929            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
930            -i64::MAX as i128 * 1_000_000
931        );
932    }
933    #[test]
934    fn test_duration_microseconds_min_underflow() {
935        // This test establishes that a TimeDelta can store more microseconds than
936        // are representable through the return of duration.num_microseconds().
937        let duration = TimeDelta::microseconds(i64::MIN) - TimeDelta::microseconds(1);
938        assert!(duration.num_microseconds().is_none());
939        assert_eq!(
940            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
941            (i64::MIN as i128 - 1) * 1_000
942        );
943        // Here we ensure that trying to subtract one microsecond from the minimum
944        // storable value will fail.
945        assert!(
946            TimeDelta::try_milliseconds(-i64::MAX)
947                .unwrap()
948                .checked_sub(&TimeDelta::microseconds(1))
949                .is_none()
950        );
951    }
952
953    #[test]
954    fn test_duration_num_nanoseconds() {
955        assert_eq!(TimeDelta::zero().num_nanoseconds(), Some(0));
956        assert_eq!(TimeDelta::nanoseconds(1).num_nanoseconds(), Some(1));
957        assert_eq!(TimeDelta::nanoseconds(-1).num_nanoseconds(), Some(-1));
958
959        // overflow checks
960        const NANOS_PER_DAY: i64 = 86_400_000_000_000;
961        assert_eq!(
962            TimeDelta::try_days(i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
963            Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
964        );
965        assert_eq!(
966            TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
967            Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
968        );
969        assert_eq!(
970            TimeDelta::try_days(i64::MAX / NANOS_PER_DAY + 1).unwrap().num_nanoseconds(),
971            None
972        );
973        assert_eq!(
974            TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY - 1).unwrap().num_nanoseconds(),
975            None
976        );
977    }
978    #[test]
979    fn test_duration_nanoseconds_max_allowed() {
980        // The number of nanoseconds acceptable through the constructor is far fewer
981        // than the number that can actually be stored in a TimeDelta, so this is not
982        // a particular insightful test.
983        let duration = TimeDelta::nanoseconds(i64::MAX);
984        assert_eq!(duration.num_nanoseconds(), Some(i64::MAX));
985        assert_eq!(
986            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
987            i64::MAX as i128
988        );
989        // Here we create a TimeDelta with the maximum possible number of nanoseconds
990        // by creating a TimeDelta with the maximum number of milliseconds and then
991        // checking that the number of nanoseconds matches the storage limit.
992        let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
993        assert!(duration.num_nanoseconds().is_none());
994        assert_eq!(
995            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
996            i64::MAX as i128 * 1_000_000
997        );
998    }
999
1000    #[test]
1001    fn test_duration_nanoseconds_max_overflow() {
1002        // This test establishes that a TimeDelta can store more nanoseconds than are
1003        // representable through the return of duration.num_nanoseconds().
1004        let duration = TimeDelta::nanoseconds(i64::MAX) + TimeDelta::nanoseconds(1);
1005        assert!(duration.num_nanoseconds().is_none());
1006        assert_eq!(
1007            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1008            i64::MAX as i128 + 1
1009        );
1010        // Here we ensure that trying to add one nanosecond to the maximum storable
1011        // value will fail.
1012        assert!(
1013            TimeDelta::try_milliseconds(i64::MAX)
1014                .unwrap()
1015                .checked_add(&TimeDelta::nanoseconds(1))
1016                .is_none()
1017        );
1018    }
1019
1020    #[test]
1021    fn test_duration_nanoseconds_min_allowed() {
1022        // The number of nanoseconds acceptable through the constructor is far fewer
1023        // than the number that can actually be stored in a TimeDelta, so this is not
1024        // a particular insightful test.
1025        let duration = TimeDelta::nanoseconds(i64::MIN);
1026        assert_eq!(duration.num_nanoseconds(), Some(i64::MIN));
1027        assert_eq!(
1028            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1029            i64::MIN as i128
1030        );
1031        // Here we create a TimeDelta with the minimum possible number of nanoseconds
1032        // by creating a TimeDelta with the minimum number of milliseconds and then
1033        // checking that the number of nanoseconds matches the storage limit.
1034        let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
1035        assert!(duration.num_nanoseconds().is_none());
1036        assert_eq!(
1037            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1038            -i64::MAX as i128 * 1_000_000
1039        );
1040    }
1041
1042    #[test]
1043    fn test_duration_nanoseconds_min_underflow() {
1044        // This test establishes that a TimeDelta can store more nanoseconds than are
1045        // representable through the return of duration.num_nanoseconds().
1046        let duration = TimeDelta::nanoseconds(i64::MIN) - TimeDelta::nanoseconds(1);
1047        assert!(duration.num_nanoseconds().is_none());
1048        assert_eq!(
1049            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1050            i64::MIN as i128 - 1
1051        );
1052        // Here we ensure that trying to subtract one nanosecond from the minimum
1053        // storable value will fail.
1054        assert!(
1055            TimeDelta::try_milliseconds(-i64::MAX)
1056                .unwrap()
1057                .checked_sub(&TimeDelta::nanoseconds(1))
1058                .is_none()
1059        );
1060    }
1061
1062    #[test]
1063    fn test_max() {
1064        assert_eq!(
1065            MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128,
1066            i64::MAX as i128 * 1_000_000
1067        );
1068        assert_eq!(MAX, TimeDelta::try_milliseconds(i64::MAX).unwrap());
1069        assert_eq!(MAX.num_milliseconds(), i64::MAX);
1070        assert_eq!(MAX.num_microseconds(), None);
1071        assert_eq!(MAX.num_nanoseconds(), None);
1072    }
1073
1074    #[test]
1075    fn test_min() {
1076        assert_eq!(
1077            MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128,
1078            -i64::MAX as i128 * 1_000_000
1079        );
1080        assert_eq!(MIN, TimeDelta::try_milliseconds(-i64::MAX).unwrap());
1081        assert_eq!(MIN.num_milliseconds(), -i64::MAX);
1082        assert_eq!(MIN.num_microseconds(), None);
1083        assert_eq!(MIN.num_nanoseconds(), None);
1084    }
1085
1086    #[test]
1087    fn test_duration_ord() {
1088        let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1089
1090        assert!(milliseconds(1) < milliseconds(2));
1091        assert!(milliseconds(2) > milliseconds(1));
1092        assert!(milliseconds(-1) > milliseconds(-2));
1093        assert!(milliseconds(-2) < milliseconds(-1));
1094        assert!(milliseconds(-1) < milliseconds(1));
1095        assert!(milliseconds(1) > milliseconds(-1));
1096        assert!(milliseconds(0) < milliseconds(1));
1097        assert!(milliseconds(0) > milliseconds(-1));
1098        assert!(milliseconds(1_001) < milliseconds(1_002));
1099        assert!(milliseconds(-1_001) > milliseconds(-1_002));
1100        assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891));
1101        assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891));
1102        assert!(milliseconds(i64::MAX) > milliseconds(i64::MAX - 1));
1103        assert!(milliseconds(-i64::MAX) < milliseconds(-i64::MAX + 1));
1104    }
1105
1106    #[test]
1107    fn test_duration_checked_ops() {
1108        let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1109        let seconds = |s| TimeDelta::try_seconds(s).unwrap();
1110
1111        assert_eq!(
1112            milliseconds(i64::MAX).checked_add(&milliseconds(0)),
1113            Some(milliseconds(i64::MAX))
1114        );
1115        assert_eq!(
1116            milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
1117            Some(milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
1118        );
1119        assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::microseconds(1000)).is_none());
1120        assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::nanoseconds(1)).is_none());
1121
1122        assert_eq!(
1123            milliseconds(-i64::MAX).checked_sub(&milliseconds(0)),
1124            Some(milliseconds(-i64::MAX))
1125        );
1126        assert_eq!(
1127            milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
1128            Some(milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
1129        );
1130        assert!(milliseconds(-i64::MAX).checked_sub(&milliseconds(1)).is_none());
1131        assert!(milliseconds(-i64::MAX).checked_sub(&TimeDelta::nanoseconds(1)).is_none());
1132
1133        assert!(seconds(i64::MAX / 1000).checked_mul(2000).is_none());
1134        assert!(seconds(i64::MIN / 1000).checked_mul(2000).is_none());
1135        assert!(seconds(1).checked_div(0).is_none());
1136    }
1137
1138    #[test]
1139    fn test_duration_abs() {
1140        let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1141
1142        assert_eq!(milliseconds(1300).abs(), milliseconds(1300));
1143        assert_eq!(milliseconds(1000).abs(), milliseconds(1000));
1144        assert_eq!(milliseconds(300).abs(), milliseconds(300));
1145        assert_eq!(milliseconds(0).abs(), milliseconds(0));
1146        assert_eq!(milliseconds(-300).abs(), milliseconds(300));
1147        assert_eq!(milliseconds(-700).abs(), milliseconds(700));
1148        assert_eq!(milliseconds(-1000).abs(), milliseconds(1000));
1149        assert_eq!(milliseconds(-1300).abs(), milliseconds(1300));
1150        assert_eq!(milliseconds(-1700).abs(), milliseconds(1700));
1151        assert_eq!(milliseconds(-i64::MAX).abs(), milliseconds(i64::MAX));
1152    }
1153
1154    #[test]
1155    #[allow(clippy::erasing_op)]
1156    fn test_duration_mul() {
1157        assert_eq!(TimeDelta::zero() * i32::MAX, TimeDelta::zero());
1158        assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero());
1159        assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero());
1160        assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1));
1161        assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::try_seconds(1).unwrap());
1162        assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1163        assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1164        assert_eq!(
1165            TimeDelta::nanoseconds(30) * 333_333_333,
1166            TimeDelta::try_seconds(10).unwrap() - TimeDelta::nanoseconds(10)
1167        );
1168        assert_eq!(
1169            (TimeDelta::nanoseconds(1)
1170                + TimeDelta::try_seconds(1).unwrap()
1171                + TimeDelta::try_days(1).unwrap())
1172                * 3,
1173            TimeDelta::nanoseconds(3)
1174                + TimeDelta::try_seconds(3).unwrap()
1175                + TimeDelta::try_days(3).unwrap()
1176        );
1177        assert_eq!(
1178            TimeDelta::try_milliseconds(1500).unwrap() * -2,
1179            TimeDelta::try_seconds(-3).unwrap()
1180        );
1181        assert_eq!(
1182            TimeDelta::try_milliseconds(-1500).unwrap() * 2,
1183            TimeDelta::try_seconds(-3).unwrap()
1184        );
1185    }
1186
1187    #[test]
1188    fn test_duration_div() {
1189        assert_eq!(TimeDelta::zero() / i32::MAX, TimeDelta::zero());
1190        assert_eq!(TimeDelta::zero() / i32::MIN, TimeDelta::zero());
1191        assert_eq!(TimeDelta::nanoseconds(123_456_789) / 1, TimeDelta::nanoseconds(123_456_789));
1192        assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789));
1193        assert_eq!(-TimeDelta::nanoseconds(123_456_789) / -1, TimeDelta::nanoseconds(123_456_789));
1194        assert_eq!(-TimeDelta::nanoseconds(123_456_789) / 1, -TimeDelta::nanoseconds(123_456_789));
1195        assert_eq!(TimeDelta::try_seconds(1).unwrap() / 3, TimeDelta::nanoseconds(333_333_333));
1196        assert_eq!(TimeDelta::try_seconds(4).unwrap() / 3, TimeDelta::nanoseconds(1_333_333_333));
1197        assert_eq!(
1198            TimeDelta::try_seconds(-1).unwrap() / 2,
1199            TimeDelta::try_milliseconds(-500).unwrap()
1200        );
1201        assert_eq!(
1202            TimeDelta::try_seconds(1).unwrap() / -2,
1203            TimeDelta::try_milliseconds(-500).unwrap()
1204        );
1205        assert_eq!(
1206            TimeDelta::try_seconds(-1).unwrap() / -2,
1207            TimeDelta::try_milliseconds(500).unwrap()
1208        );
1209        assert_eq!(TimeDelta::try_seconds(-4).unwrap() / 3, TimeDelta::nanoseconds(-1_333_333_333));
1210        assert_eq!(TimeDelta::try_seconds(-4).unwrap() / -3, TimeDelta::nanoseconds(1_333_333_333));
1211    }
1212
1213    #[test]
1214    fn test_duration_sum() {
1215        let duration_list_1 = [TimeDelta::zero(), TimeDelta::try_seconds(1).unwrap()];
1216        let sum_1: TimeDelta = duration_list_1.iter().sum();
1217        assert_eq!(sum_1, TimeDelta::try_seconds(1).unwrap());
1218
1219        let duration_list_2 = [
1220            TimeDelta::zero(),
1221            TimeDelta::try_seconds(1).unwrap(),
1222            TimeDelta::try_seconds(6).unwrap(),
1223            TimeDelta::try_seconds(10).unwrap(),
1224        ];
1225        let sum_2: TimeDelta = duration_list_2.iter().sum();
1226        assert_eq!(sum_2, TimeDelta::try_seconds(17).unwrap());
1227
1228        let duration_arr = [
1229            TimeDelta::zero(),
1230            TimeDelta::try_seconds(1).unwrap(),
1231            TimeDelta::try_seconds(6).unwrap(),
1232            TimeDelta::try_seconds(10).unwrap(),
1233        ];
1234        let sum_3: TimeDelta = duration_arr.into_iter().sum();
1235        assert_eq!(sum_3, TimeDelta::try_seconds(17).unwrap());
1236    }
1237
1238    #[test]
1239    fn test_duration_fmt() {
1240        assert_eq!(TimeDelta::zero().to_string(), "P0D");
1241        assert_eq!(TimeDelta::try_days(42).unwrap().to_string(), "PT3628800S");
1242        assert_eq!(TimeDelta::try_days(-42).unwrap().to_string(), "-PT3628800S");
1243        assert_eq!(TimeDelta::try_seconds(42).unwrap().to_string(), "PT42S");
1244        assert_eq!(TimeDelta::try_milliseconds(42).unwrap().to_string(), "PT0.042S");
1245        assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S");
1246        assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S");
1247        assert_eq!(
1248            (TimeDelta::try_days(7).unwrap() + TimeDelta::try_milliseconds(6543).unwrap())
1249                .to_string(),
1250            "PT604806.543S"
1251        );
1252        assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().to_string(), "-PT86401S");
1253        assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S");
1254
1255        // the format specifier should have no effect on `TimeDelta`
1256        assert_eq!(
1257            format!(
1258                "{:30}",
1259                TimeDelta::try_days(1).unwrap() + TimeDelta::try_milliseconds(2345).unwrap()
1260            ),
1261            "PT86402.345S"
1262        );
1263    }
1264
1265    #[test]
1266    fn test_to_std() {
1267        assert_eq!(TimeDelta::try_seconds(1).unwrap().to_std(), Ok(Duration::new(1, 0)));
1268        assert_eq!(TimeDelta::try_seconds(86_401).unwrap().to_std(), Ok(Duration::new(86_401, 0)));
1269        assert_eq!(
1270            TimeDelta::try_milliseconds(123).unwrap().to_std(),
1271            Ok(Duration::new(0, 123_000_000))
1272        );
1273        assert_eq!(
1274            TimeDelta::try_milliseconds(123_765).unwrap().to_std(),
1275            Ok(Duration::new(123, 765_000_000))
1276        );
1277        assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777)));
1278        assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000)));
1279        assert_eq!(TimeDelta::try_seconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1280        assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1281    }
1282
1283    #[test]
1284    fn test_from_std() {
1285        assert_eq!(
1286            Ok(TimeDelta::try_seconds(1).unwrap()),
1287            TimeDelta::from_std(Duration::new(1, 0))
1288        );
1289        assert_eq!(
1290            Ok(TimeDelta::try_seconds(86_401).unwrap()),
1291            TimeDelta::from_std(Duration::new(86_401, 0))
1292        );
1293        assert_eq!(
1294            Ok(TimeDelta::try_milliseconds(123).unwrap()),
1295            TimeDelta::from_std(Duration::new(0, 123_000_000))
1296        );
1297        assert_eq!(
1298            Ok(TimeDelta::try_milliseconds(123_765).unwrap()),
1299            TimeDelta::from_std(Duration::new(123, 765_000_000))
1300        );
1301        assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777)));
1302        assert_eq!(Ok(MAX), TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_000)));
1303        assert_eq!(
1304            TimeDelta::from_std(Duration::new(9_223_372_036_854_776, 0)),
1305            Err(OutOfRangeError(()))
1306        );
1307        assert_eq!(
1308            TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_001)),
1309            Err(OutOfRangeError(()))
1310        );
1311    }
1312
1313    #[test]
1314    fn test_duration_const() {
1315        const ONE_WEEK: TimeDelta = expect(TimeDelta::try_weeks(1), "");
1316        const ONE_DAY: TimeDelta = expect(TimeDelta::try_days(1), "");
1317        const ONE_HOUR: TimeDelta = expect(TimeDelta::try_hours(1), "");
1318        const ONE_MINUTE: TimeDelta = expect(TimeDelta::try_minutes(1), "");
1319        const ONE_SECOND: TimeDelta = expect(TimeDelta::try_seconds(1), "");
1320        const ONE_MILLI: TimeDelta = expect(TimeDelta::try_milliseconds(1), "");
1321        const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1);
1322        const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1);
1323        let combo: TimeDelta = ONE_WEEK
1324            + ONE_DAY
1325            + ONE_HOUR
1326            + ONE_MINUTE
1327            + ONE_SECOND
1328            + ONE_MILLI
1329            + ONE_MICRO
1330            + ONE_NANO;
1331
1332        assert!(ONE_WEEK != TimeDelta::zero());
1333        assert!(ONE_DAY != TimeDelta::zero());
1334        assert!(ONE_HOUR != TimeDelta::zero());
1335        assert!(ONE_MINUTE != TimeDelta::zero());
1336        assert!(ONE_SECOND != TimeDelta::zero());
1337        assert!(ONE_MILLI != TimeDelta::zero());
1338        assert!(ONE_MICRO != TimeDelta::zero());
1339        assert!(ONE_NANO != TimeDelta::zero());
1340        assert_eq!(
1341            combo,
1342            TimeDelta::try_seconds(86400 * 7 + 86400 + 3600 + 60 + 1).unwrap()
1343                + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000)
1344        );
1345    }
1346
1347    #[test]
1348    #[cfg(feature = "rkyv-validation")]
1349    fn test_rkyv_validation() {
1350        let duration = TimeDelta::try_seconds(1).unwrap();
1351        let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
1352        assert_eq!(rkyv::from_bytes::<TimeDelta>(&bytes).unwrap(), duration);
1353    }
1354}