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 {
305            self.secs + 1
306        } else {
307            self.secs
308        }
309    }
310
311    /// Returns the number of nanoseconds such that
312    /// `subsec_nanos() + num_seconds() * NANOS_PER_SEC` is the total number of
313    /// nanoseconds in the `TimeDelta`.
314    pub const fn subsec_nanos(&self) -> i32 {
315        if self.secs < 0 && self.nanos > 0 {
316            self.nanos - NANOS_PER_SEC
317        } else {
318            self.nanos
319        }
320    }
321
322    /// Returns the total number of whole milliseconds in the `TimeDelta`.
323    pub const fn num_milliseconds(&self) -> i64 {
324        // A proper TimeDelta will not overflow, because MIN and MAX are defined such
325        // that the range is within the bounds of an i64, from -i64::MAX through to
326        // +i64::MAX inclusive. Notably, i64::MIN is excluded from this range.
327        let secs_part = self.num_seconds() * MILLIS_PER_SEC;
328        let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI;
329        secs_part + nanos_part as i64
330    }
331
332    /// Returns the total number of whole microseconds in the `TimeDelta`,
333    /// or `None` on overflow (exceeding 2^63 microseconds in either direction).
334    pub const fn num_microseconds(&self) -> Option<i64> {
335        let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
336        let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO;
337        secs_part.checked_add(nanos_part as i64)
338    }
339
340    /// Returns the total number of whole nanoseconds in the `TimeDelta`,
341    /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
342    pub const fn num_nanoseconds(&self) -> Option<i64> {
343        let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
344        let nanos_part = self.subsec_nanos();
345        secs_part.checked_add(nanos_part as i64)
346    }
347
348    /// Add two `TimeDelta`s, returning `None` if overflow occurred.
349    #[must_use]
350    pub const fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
351        // No overflow checks here because we stay comfortably within the range of an `i64`.
352        // Range checks happen in `TimeDelta::new`.
353        let mut secs = self.secs + rhs.secs;
354        let mut nanos = self.nanos + rhs.nanos;
355        if nanos >= NANOS_PER_SEC {
356            nanos -= NANOS_PER_SEC;
357            secs += 1;
358        }
359        TimeDelta::new(secs, nanos as u32)
360    }
361
362    /// Subtract two `TimeDelta`s, returning `None` if overflow occurred.
363    #[must_use]
364    pub const fn checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
365        // No overflow checks here because we stay comfortably within the range of an `i64`.
366        // Range checks happen in `TimeDelta::new`.
367        let mut secs = self.secs - rhs.secs;
368        let mut nanos = self.nanos - rhs.nanos;
369        if nanos < 0 {
370            nanos += NANOS_PER_SEC;
371            secs -= 1;
372        }
373        TimeDelta::new(secs, nanos as u32)
374    }
375
376    /// Multiply a `TimeDelta` with a i32, returning `None` if overflow occurred.
377    #[must_use]
378    pub const fn checked_mul(&self, rhs: i32) -> Option<TimeDelta> {
379        // Multiply nanoseconds as i64, because it cannot overflow that way.
380        let total_nanos = self.nanos as i64 * rhs as i64;
381        let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
382        // Multiply seconds as i128 to prevent overflow
383        let secs: i128 = self.secs as i128 * rhs as i128 + extra_secs as i128;
384        if secs <= i64::MIN as i128 || secs >= i64::MAX as i128 {
385            return None;
386        };
387        Some(TimeDelta { secs: secs as i64, nanos: nanos as i32 })
388    }
389
390    /// Divide a `TimeDelta` with a i32, returning `None` if dividing by 0.
391    #[must_use]
392    pub const fn checked_div(&self, rhs: i32) -> Option<TimeDelta> {
393        if rhs == 0 {
394            return None;
395        }
396        let secs = self.secs / rhs as i64;
397        let carry = self.secs % rhs as i64;
398        let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64;
399        let nanos = self.nanos / rhs + extra_nanos as i32;
400
401        let (secs, nanos) = match nanos {
402            i32::MIN..=-1 => (secs - 1, nanos + NANOS_PER_SEC),
403            NANOS_PER_SEC..=i32::MAX => (secs + 1, nanos - NANOS_PER_SEC),
404            _ => (secs, nanos),
405        };
406
407        Some(TimeDelta { secs, nanos })
408    }
409
410    /// Returns the `TimeDelta` as an absolute (non-negative) value.
411    #[inline]
412    pub const fn abs(&self) -> TimeDelta {
413        if self.secs < 0 && self.nanos != 0 {
414            TimeDelta { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos }
415        } else {
416            TimeDelta { secs: self.secs.abs(), nanos: self.nanos }
417        }
418    }
419
420    /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
421    #[deprecated(since = "0.4.39", note = "Use `TimeDelta::MIN` instead")]
422    #[inline]
423    pub const fn min_value() -> TimeDelta {
424        MIN
425    }
426
427    /// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
428    #[deprecated(since = "0.4.39", note = "Use `TimeDelta::MAX` instead")]
429    #[inline]
430    pub const fn max_value() -> TimeDelta {
431        MAX
432    }
433
434    /// A `TimeDelta` where the stored seconds and nanoseconds are equal to zero.
435    #[inline]
436    pub const fn zero() -> TimeDelta {
437        TimeDelta { secs: 0, nanos: 0 }
438    }
439
440    /// Returns `true` if the `TimeDelta` equals `TimeDelta::zero()`.
441    #[inline]
442    pub const fn is_zero(&self) -> bool {
443        self.secs == 0 && self.nanos == 0
444    }
445
446    /// Creates a `TimeDelta` object from `std::time::Duration`
447    ///
448    /// This function errors when original duration is larger than the maximum
449    /// value supported for this type.
450    pub const fn from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError> {
451        // We need to check secs as u64 before coercing to i64
452        if duration.as_secs() > MAX.secs as u64 {
453            return Err(OutOfRangeError(()));
454        }
455        match TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos()) {
456            Some(d) => Ok(d),
457            None => Err(OutOfRangeError(())),
458        }
459    }
460
461    /// Creates a `std::time::Duration` object from a `TimeDelta`.
462    ///
463    /// This function errors when duration is less than zero. As standard
464    /// library implementation is limited to non-negative values.
465    pub const fn to_std(&self) -> Result<Duration, OutOfRangeError> {
466        if self.secs < 0 {
467            return Err(OutOfRangeError(()));
468        }
469        Ok(Duration::new(self.secs as u64, self.nanos as u32))
470    }
471
472    /// This duplicates `Neg::neg` because trait methods can't be const yet.
473    pub(crate) const fn neg(self) -> TimeDelta {
474        let (secs_diff, nanos) = match self.nanos {
475            0 => (0, 0),
476            nanos => (1, NANOS_PER_SEC - nanos),
477        };
478        TimeDelta { secs: -self.secs - secs_diff, nanos }
479    }
480
481    /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
482    pub const MIN: Self = MIN;
483
484    /// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
485    pub const MAX: Self = MAX;
486}
487
488impl Neg for TimeDelta {
489    type Output = TimeDelta;
490
491    #[inline]
492    fn neg(self) -> TimeDelta {
493        let (secs_diff, nanos) = match self.nanos {
494            0 => (0, 0),
495            nanos => (1, NANOS_PER_SEC - nanos),
496        };
497        TimeDelta { secs: -self.secs - secs_diff, nanos }
498    }
499}
500
501impl Add for TimeDelta {
502    type Output = TimeDelta;
503
504    fn add(self, rhs: TimeDelta) -> TimeDelta {
505        self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed")
506    }
507}
508
509impl Sub for TimeDelta {
510    type Output = TimeDelta;
511
512    fn sub(self, rhs: TimeDelta) -> TimeDelta {
513        self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed")
514    }
515}
516
517impl AddAssign for TimeDelta {
518    fn add_assign(&mut self, rhs: TimeDelta) {
519        let new = self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed");
520        *self = new;
521    }
522}
523
524impl SubAssign for TimeDelta {
525    fn sub_assign(&mut self, rhs: TimeDelta) {
526        let new = self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed");
527        *self = new;
528    }
529}
530
531impl Mul<i32> for TimeDelta {
532    type Output = TimeDelta;
533
534    fn mul(self, rhs: i32) -> TimeDelta {
535        self.checked_mul(rhs).expect("`TimeDelta * i32` overflowed")
536    }
537}
538
539impl Div<i32> for TimeDelta {
540    type Output = TimeDelta;
541
542    fn div(self, rhs: i32) -> TimeDelta {
543        self.checked_div(rhs).expect("`i32` is zero")
544    }
545}
546
547impl<'a> core::iter::Sum<&'a TimeDelta> for TimeDelta {
548    fn sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta {
549        iter.fold(TimeDelta::zero(), |acc, x| acc + *x)
550    }
551}
552
553impl core::iter::Sum<TimeDelta> for TimeDelta {
554    fn sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta {
555        iter.fold(TimeDelta::zero(), |acc, x| acc + x)
556    }
557}
558
559impl fmt::Display for TimeDelta {
560    /// Format a `TimeDelta` using the [ISO 8601] format
561    ///
562    /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601#Durations
563    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
564        // technically speaking, negative duration is not valid ISO 8601,
565        // but we need to print it anyway.
566        let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
567
568        write!(f, "{}P", sign)?;
569        // Plenty of ways to encode an empty string. `P0D` is short and not too strange.
570        if abs.secs == 0 && abs.nanos == 0 {
571            return f.write_str("0D");
572        }
573
574        f.write_fmt(format_args!("T{}", abs.secs))?;
575
576        if abs.nanos > 0 {
577            // Count the number of significant digits, while removing all trailing zero's.
578            let mut figures = 9usize;
579            let mut fraction_digits = abs.nanos;
580            loop {
581                let div = fraction_digits / 10;
582                let last_digit = fraction_digits % 10;
583                if last_digit != 0 {
584                    break;
585                }
586                fraction_digits = div;
587                figures -= 1;
588            }
589            f.write_fmt(format_args!(".{:01$}", fraction_digits, figures))?;
590        }
591        f.write_str("S")?;
592        Ok(())
593    }
594}
595
596/// Represents error when converting `TimeDelta` to/from a standard library
597/// implementation
598///
599/// The `std::time::Duration` supports a range from zero to `u64::MAX`
600/// *seconds*, while this module supports signed range of up to
601/// `i64::MAX` of *milliseconds*.
602#[derive(Debug, Clone, Copy, PartialEq, Eq)]
603pub struct OutOfRangeError(());
604
605impl fmt::Display for OutOfRangeError {
606    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
607        write!(f, "Source duration value is out of range for the target type")
608    }
609}
610
611#[cfg(feature = "std")]
612impl Error for OutOfRangeError {
613    #[allow(deprecated)]
614    fn description(&self) -> &str {
615        "out of range error"
616    }
617}
618
619#[inline]
620const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
621    (this.div_euclid(other), this.rem_euclid(other))
622}
623
624#[cfg(all(feature = "arbitrary", feature = "std"))]
625impl arbitrary::Arbitrary<'_> for TimeDelta {
626    fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta> {
627        const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1;
628        const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
629
630        let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
631        let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?;
632        let duration = TimeDelta { secs, nanos };
633
634        if duration < MIN || duration > MAX {
635            Err(arbitrary::Error::IncorrectFormat)
636        } else {
637            Ok(duration)
638        }
639    }
640}
641
642#[cfg(feature = "serde")]
643mod serde {
644    use super::TimeDelta;
645    use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
646
647    impl Serialize for TimeDelta {
648        fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
649            <(i64, i32) as Serialize>::serialize(&(self.secs, self.nanos), serializer)
650        }
651    }
652
653    impl<'de> Deserialize<'de> for TimeDelta {
654        fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
655            let (secs, nanos) = <(i64, i32) as Deserialize>::deserialize(deserializer)?;
656            TimeDelta::new(secs, nanos as u32).ok_or(Error::custom("TimeDelta out of bounds"))
657        }
658    }
659
660    #[cfg(test)]
661    mod tests {
662        use super::{super::MAX, TimeDelta};
663
664        #[test]
665        fn test_serde() {
666            let duration = TimeDelta::new(123, 456).unwrap();
667            assert_eq!(
668                serde_json::from_value::<TimeDelta>(serde_json::to_value(duration).unwrap())
669                    .unwrap(),
670                duration
671            );
672        }
673
674        #[test]
675        #[should_panic(expected = "TimeDelta out of bounds")]
676        fn test_serde_oob_panic() {
677            let _ =
678                serde_json::from_value::<TimeDelta>(serde_json::json!([MAX.secs + 1, 0])).unwrap();
679        }
680    }
681}
682
683#[cfg(test)]
684mod tests {
685    use super::OutOfRangeError;
686    use super::{TimeDelta, MAX, MIN};
687    use crate::expect;
688    use core::time::Duration;
689
690    #[test]
691    fn test_duration() {
692        let days = |d| TimeDelta::try_days(d).unwrap();
693        let seconds = |s| TimeDelta::try_seconds(s).unwrap();
694
695        assert!(seconds(1) != TimeDelta::zero());
696        assert_eq!(seconds(1) + seconds(2), seconds(3));
697        assert_eq!(seconds(86_399) + seconds(4), days(1) + seconds(3));
698        assert_eq!(days(10) - seconds(1000), seconds(863_000));
699        assert_eq!(days(10) - seconds(1_000_000), seconds(-136_000));
700        assert_eq!(
701            days(2) + seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
702            days(3) + TimeDelta::nanoseconds(234_567_890)
703        );
704        assert_eq!(-days(3), days(-3));
705        assert_eq!(-(days(3) + seconds(70)), days(-4) + seconds(86_400 - 70));
706
707        let mut d = TimeDelta::default();
708        d += TimeDelta::try_minutes(1).unwrap();
709        d -= seconds(30);
710        assert_eq!(d, seconds(30));
711    }
712
713    #[test]
714    fn test_duration_num_days() {
715        assert_eq!(TimeDelta::zero().num_days(), 0);
716        assert_eq!(TimeDelta::try_days(1).unwrap().num_days(), 1);
717        assert_eq!(TimeDelta::try_days(-1).unwrap().num_days(), -1);
718        assert_eq!(TimeDelta::try_seconds(86_399).unwrap().num_days(), 0);
719        assert_eq!(TimeDelta::try_seconds(86_401).unwrap().num_days(), 1);
720        assert_eq!(TimeDelta::try_seconds(-86_399).unwrap().num_days(), 0);
721        assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().num_days(), -1);
722        assert_eq!(TimeDelta::try_days(i32::MAX as i64).unwrap().num_days(), i32::MAX as i64);
723        assert_eq!(TimeDelta::try_days(i32::MIN as i64).unwrap().num_days(), i32::MIN as i64);
724    }
725
726    #[test]
727    fn test_duration_num_seconds() {
728        assert_eq!(TimeDelta::zero().num_seconds(), 0);
729        assert_eq!(TimeDelta::try_seconds(1).unwrap().num_seconds(), 1);
730        assert_eq!(TimeDelta::try_seconds(-1).unwrap().num_seconds(), -1);
731        assert_eq!(TimeDelta::try_milliseconds(999).unwrap().num_seconds(), 0);
732        assert_eq!(TimeDelta::try_milliseconds(1001).unwrap().num_seconds(), 1);
733        assert_eq!(TimeDelta::try_milliseconds(-999).unwrap().num_seconds(), 0);
734        assert_eq!(TimeDelta::try_milliseconds(-1001).unwrap().num_seconds(), -1);
735    }
736
737    #[test]
738    fn test_duration_seconds_max_allowed() {
739        let duration = TimeDelta::try_seconds(i64::MAX / 1_000).unwrap();
740        assert_eq!(duration.num_seconds(), i64::MAX / 1_000);
741        assert_eq!(
742            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
743            i64::MAX as i128 / 1_000 * 1_000_000_000
744        );
745    }
746
747    #[test]
748    fn test_duration_seconds_max_overflow() {
749        assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none());
750    }
751
752    #[test]
753    #[should_panic(expected = "TimeDelta::seconds out of bounds")]
754    fn test_duration_seconds_max_overflow_panic() {
755        let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
756    }
757
758    #[test]
759    fn test_duration_seconds_min_allowed() {
760        let duration = TimeDelta::try_seconds(i64::MIN / 1_000).unwrap(); // Same as -i64::MAX / 1_000 due to rounding
761        assert_eq!(duration.num_seconds(), i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding
762        assert_eq!(
763            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
764            -i64::MAX as i128 / 1_000 * 1_000_000_000
765        );
766    }
767
768    #[test]
769    fn test_duration_seconds_min_underflow() {
770        assert!(TimeDelta::try_seconds(-i64::MAX / 1_000 - 1).is_none());
771    }
772
773    #[test]
774    #[should_panic(expected = "TimeDelta::seconds out of bounds")]
775    fn test_duration_seconds_min_underflow_panic() {
776        let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1);
777    }
778
779    #[test]
780    fn test_duration_num_milliseconds() {
781        assert_eq!(TimeDelta::zero().num_milliseconds(), 0);
782        assert_eq!(TimeDelta::try_milliseconds(1).unwrap().num_milliseconds(), 1);
783        assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().num_milliseconds(), -1);
784        assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0);
785        assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1);
786        assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0);
787        assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1);
788    }
789
790    #[test]
791    fn test_duration_milliseconds_max_allowed() {
792        // The maximum number of milliseconds acceptable through the constructor is
793        // equal to the number that can be stored in a TimeDelta.
794        let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
795        assert_eq!(duration.num_milliseconds(), i64::MAX);
796        assert_eq!(
797            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
798            i64::MAX as i128 * 1_000_000
799        );
800    }
801
802    #[test]
803    fn test_duration_milliseconds_max_overflow() {
804        // Here we ensure that trying to add one millisecond to the maximum storable
805        // value will fail.
806        assert!(TimeDelta::try_milliseconds(i64::MAX)
807            .unwrap()
808            .checked_add(&TimeDelta::try_milliseconds(1).unwrap())
809            .is_none());
810    }
811
812    #[test]
813    fn test_duration_milliseconds_min_allowed() {
814        // The minimum number of milliseconds acceptable through the constructor is
815        // not equal to the number that can be stored in a TimeDelta - there is a
816        // difference of one (i64::MIN vs -i64::MAX).
817        let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
818        assert_eq!(duration.num_milliseconds(), -i64::MAX);
819        assert_eq!(
820            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
821            -i64::MAX as i128 * 1_000_000
822        );
823    }
824
825    #[test]
826    fn test_duration_milliseconds_min_underflow() {
827        // Here we ensure that trying to subtract one millisecond from the minimum
828        // storable value will fail.
829        assert!(TimeDelta::try_milliseconds(-i64::MAX)
830            .unwrap()
831            .checked_sub(&TimeDelta::try_milliseconds(1).unwrap())
832            .is_none());
833    }
834
835    #[test]
836    #[should_panic(expected = "TimeDelta::milliseconds out of bounds")]
837    fn test_duration_milliseconds_min_underflow_panic() {
838        // Here we ensure that trying to create a value one millisecond below the
839        // minimum storable value will fail. This test is necessary because the
840        // storable range is -i64::MAX, but the constructor type of i64 will allow
841        // i64::MIN, which is one value below.
842        let _ = TimeDelta::milliseconds(i64::MIN); // Same as -i64::MAX - 1
843    }
844
845    #[test]
846    fn test_duration_num_microseconds() {
847        assert_eq!(TimeDelta::zero().num_microseconds(), Some(0));
848        assert_eq!(TimeDelta::microseconds(1).num_microseconds(), Some(1));
849        assert_eq!(TimeDelta::microseconds(-1).num_microseconds(), Some(-1));
850        assert_eq!(TimeDelta::nanoseconds(999).num_microseconds(), Some(0));
851        assert_eq!(TimeDelta::nanoseconds(1001).num_microseconds(), Some(1));
852        assert_eq!(TimeDelta::nanoseconds(-999).num_microseconds(), Some(0));
853        assert_eq!(TimeDelta::nanoseconds(-1001).num_microseconds(), Some(-1));
854
855        // overflow checks
856        const MICROS_PER_DAY: i64 = 86_400_000_000;
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).unwrap().num_microseconds(),
863            Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
864        );
865        assert_eq!(
866            TimeDelta::try_days(i64::MAX / MICROS_PER_DAY + 1).unwrap().num_microseconds(),
867            None
868        );
869        assert_eq!(
870            TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY - 1).unwrap().num_microseconds(),
871            None
872        );
873    }
874    #[test]
875    fn test_duration_microseconds_max_allowed() {
876        // The number of microseconds acceptable through the constructor is far
877        // fewer than the number that can actually be stored in a TimeDelta, so this
878        // is not a particular insightful test.
879        let duration = TimeDelta::microseconds(i64::MAX);
880        assert_eq!(duration.num_microseconds(), Some(i64::MAX));
881        assert_eq!(
882            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
883            i64::MAX as i128 * 1_000
884        );
885        // Here we create a TimeDelta with the maximum possible number of
886        // microseconds by creating a TimeDelta with the maximum number of
887        // milliseconds and then checking that the number of microseconds matches
888        // the storage limit.
889        let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
890        assert!(duration.num_microseconds().is_none());
891        assert_eq!(
892            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
893            i64::MAX as i128 * 1_000_000
894        );
895    }
896    #[test]
897    fn test_duration_microseconds_max_overflow() {
898        // This test establishes that a TimeDelta can store more microseconds than
899        // are representable through the return of duration.num_microseconds().
900        let duration = TimeDelta::microseconds(i64::MAX) + TimeDelta::microseconds(1);
901        assert!(duration.num_microseconds().is_none());
902        assert_eq!(
903            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
904            (i64::MAX as i128 + 1) * 1_000
905        );
906        // Here we ensure that trying to add one microsecond to the maximum storable
907        // value will fail.
908        assert!(TimeDelta::try_milliseconds(i64::MAX)
909            .unwrap()
910            .checked_add(&TimeDelta::microseconds(1))
911            .is_none());
912    }
913    #[test]
914    fn test_duration_microseconds_min_allowed() {
915        // The number of microseconds acceptable through the constructor is far
916        // fewer than the number that can actually be stored in a TimeDelta, so this
917        // is not a particular insightful test.
918        let duration = TimeDelta::microseconds(i64::MIN);
919        assert_eq!(duration.num_microseconds(), Some(i64::MIN));
920        assert_eq!(
921            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
922            i64::MIN as i128 * 1_000
923        );
924        // Here we create a TimeDelta with the minimum possible number of
925        // microseconds by creating a TimeDelta with the minimum number of
926        // milliseconds and then checking that the number of microseconds matches
927        // the storage limit.
928        let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
929        assert!(duration.num_microseconds().is_none());
930        assert_eq!(
931            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
932            -i64::MAX as i128 * 1_000_000
933        );
934    }
935    #[test]
936    fn test_duration_microseconds_min_underflow() {
937        // This test establishes that a TimeDelta can store more microseconds than
938        // are representable through the return of duration.num_microseconds().
939        let duration = TimeDelta::microseconds(i64::MIN) - TimeDelta::microseconds(1);
940        assert!(duration.num_microseconds().is_none());
941        assert_eq!(
942            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
943            (i64::MIN as i128 - 1) * 1_000
944        );
945        // Here we ensure that trying to subtract one microsecond from the minimum
946        // storable value will fail.
947        assert!(TimeDelta::try_milliseconds(-i64::MAX)
948            .unwrap()
949            .checked_sub(&TimeDelta::microseconds(1))
950            .is_none());
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!(TimeDelta::try_milliseconds(i64::MAX)
1013            .unwrap()
1014            .checked_add(&TimeDelta::nanoseconds(1))
1015            .is_none());
1016    }
1017
1018    #[test]
1019    fn test_duration_nanoseconds_min_allowed() {
1020        // The number of nanoseconds acceptable through the constructor is far fewer
1021        // than the number that can actually be stored in a TimeDelta, so this is not
1022        // a particular insightful test.
1023        let duration = TimeDelta::nanoseconds(i64::MIN);
1024        assert_eq!(duration.num_nanoseconds(), Some(i64::MIN));
1025        assert_eq!(
1026            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1027            i64::MIN as i128
1028        );
1029        // Here we create a TimeDelta with the minimum possible number of nanoseconds
1030        // by creating a TimeDelta with the minimum number of milliseconds and then
1031        // checking that the number of nanoseconds matches the storage limit.
1032        let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
1033        assert!(duration.num_nanoseconds().is_none());
1034        assert_eq!(
1035            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1036            -i64::MAX as i128 * 1_000_000
1037        );
1038    }
1039
1040    #[test]
1041    fn test_duration_nanoseconds_min_underflow() {
1042        // This test establishes that a TimeDelta can store more nanoseconds than are
1043        // representable through the return of duration.num_nanoseconds().
1044        let duration = TimeDelta::nanoseconds(i64::MIN) - TimeDelta::nanoseconds(1);
1045        assert!(duration.num_nanoseconds().is_none());
1046        assert_eq!(
1047            duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1048            i64::MIN as i128 - 1
1049        );
1050        // Here we ensure that trying to subtract one nanosecond from the minimum
1051        // storable value will fail.
1052        assert!(TimeDelta::try_milliseconds(-i64::MAX)
1053            .unwrap()
1054            .checked_sub(&TimeDelta::nanoseconds(1))
1055            .is_none());
1056    }
1057
1058    #[test]
1059    fn test_max() {
1060        assert_eq!(
1061            MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128,
1062            i64::MAX as i128 * 1_000_000
1063        );
1064        assert_eq!(MAX, TimeDelta::try_milliseconds(i64::MAX).unwrap());
1065        assert_eq!(MAX.num_milliseconds(), i64::MAX);
1066        assert_eq!(MAX.num_microseconds(), None);
1067        assert_eq!(MAX.num_nanoseconds(), None);
1068    }
1069
1070    #[test]
1071    fn test_min() {
1072        assert_eq!(
1073            MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128,
1074            -i64::MAX as i128 * 1_000_000
1075        );
1076        assert_eq!(MIN, TimeDelta::try_milliseconds(-i64::MAX).unwrap());
1077        assert_eq!(MIN.num_milliseconds(), -i64::MAX);
1078        assert_eq!(MIN.num_microseconds(), None);
1079        assert_eq!(MIN.num_nanoseconds(), None);
1080    }
1081
1082    #[test]
1083    fn test_duration_ord() {
1084        let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1085
1086        assert!(milliseconds(1) < milliseconds(2));
1087        assert!(milliseconds(2) > milliseconds(1));
1088        assert!(milliseconds(-1) > milliseconds(-2));
1089        assert!(milliseconds(-2) < milliseconds(-1));
1090        assert!(milliseconds(-1) < milliseconds(1));
1091        assert!(milliseconds(1) > milliseconds(-1));
1092        assert!(milliseconds(0) < milliseconds(1));
1093        assert!(milliseconds(0) > milliseconds(-1));
1094        assert!(milliseconds(1_001) < milliseconds(1_002));
1095        assert!(milliseconds(-1_001) > milliseconds(-1_002));
1096        assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891));
1097        assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891));
1098        assert!(milliseconds(i64::MAX) > milliseconds(i64::MAX - 1));
1099        assert!(milliseconds(-i64::MAX) < milliseconds(-i64::MAX + 1));
1100    }
1101
1102    #[test]
1103    fn test_duration_checked_ops() {
1104        let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1105        let seconds = |s| TimeDelta::try_seconds(s).unwrap();
1106
1107        assert_eq!(
1108            milliseconds(i64::MAX).checked_add(&milliseconds(0)),
1109            Some(milliseconds(i64::MAX))
1110        );
1111        assert_eq!(
1112            milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
1113            Some(milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
1114        );
1115        assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::microseconds(1000)).is_none());
1116        assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::nanoseconds(1)).is_none());
1117
1118        assert_eq!(
1119            milliseconds(-i64::MAX).checked_sub(&milliseconds(0)),
1120            Some(milliseconds(-i64::MAX))
1121        );
1122        assert_eq!(
1123            milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
1124            Some(milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
1125        );
1126        assert!(milliseconds(-i64::MAX).checked_sub(&milliseconds(1)).is_none());
1127        assert!(milliseconds(-i64::MAX).checked_sub(&TimeDelta::nanoseconds(1)).is_none());
1128
1129        assert!(seconds(i64::MAX / 1000).checked_mul(2000).is_none());
1130        assert!(seconds(i64::MIN / 1000).checked_mul(2000).is_none());
1131        assert!(seconds(1).checked_div(0).is_none());
1132    }
1133
1134    #[test]
1135    fn test_duration_abs() {
1136        let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1137
1138        assert_eq!(milliseconds(1300).abs(), milliseconds(1300));
1139        assert_eq!(milliseconds(1000).abs(), milliseconds(1000));
1140        assert_eq!(milliseconds(300).abs(), milliseconds(300));
1141        assert_eq!(milliseconds(0).abs(), milliseconds(0));
1142        assert_eq!(milliseconds(-300).abs(), milliseconds(300));
1143        assert_eq!(milliseconds(-700).abs(), milliseconds(700));
1144        assert_eq!(milliseconds(-1000).abs(), milliseconds(1000));
1145        assert_eq!(milliseconds(-1300).abs(), milliseconds(1300));
1146        assert_eq!(milliseconds(-1700).abs(), milliseconds(1700));
1147        assert_eq!(milliseconds(-i64::MAX).abs(), milliseconds(i64::MAX));
1148    }
1149
1150    #[test]
1151    #[allow(clippy::erasing_op)]
1152    fn test_duration_mul() {
1153        assert_eq!(TimeDelta::zero() * i32::MAX, TimeDelta::zero());
1154        assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero());
1155        assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero());
1156        assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1));
1157        assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::try_seconds(1).unwrap());
1158        assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1159        assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1160        assert_eq!(
1161            TimeDelta::nanoseconds(30) * 333_333_333,
1162            TimeDelta::try_seconds(10).unwrap() - TimeDelta::nanoseconds(10)
1163        );
1164        assert_eq!(
1165            (TimeDelta::nanoseconds(1)
1166                + TimeDelta::try_seconds(1).unwrap()
1167                + TimeDelta::try_days(1).unwrap())
1168                * 3,
1169            TimeDelta::nanoseconds(3)
1170                + TimeDelta::try_seconds(3).unwrap()
1171                + TimeDelta::try_days(3).unwrap()
1172        );
1173        assert_eq!(
1174            TimeDelta::try_milliseconds(1500).unwrap() * -2,
1175            TimeDelta::try_seconds(-3).unwrap()
1176        );
1177        assert_eq!(
1178            TimeDelta::try_milliseconds(-1500).unwrap() * 2,
1179            TimeDelta::try_seconds(-3).unwrap()
1180        );
1181    }
1182
1183    #[test]
1184    fn test_duration_div() {
1185        assert_eq!(TimeDelta::zero() / i32::MAX, TimeDelta::zero());
1186        assert_eq!(TimeDelta::zero() / i32::MIN, TimeDelta::zero());
1187        assert_eq!(TimeDelta::nanoseconds(123_456_789) / 1, TimeDelta::nanoseconds(123_456_789));
1188        assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789));
1189        assert_eq!(-TimeDelta::nanoseconds(123_456_789) / -1, TimeDelta::nanoseconds(123_456_789));
1190        assert_eq!(-TimeDelta::nanoseconds(123_456_789) / 1, -TimeDelta::nanoseconds(123_456_789));
1191        assert_eq!(TimeDelta::try_seconds(1).unwrap() / 3, TimeDelta::nanoseconds(333_333_333));
1192        assert_eq!(TimeDelta::try_seconds(4).unwrap() / 3, TimeDelta::nanoseconds(1_333_333_333));
1193        assert_eq!(
1194            TimeDelta::try_seconds(-1).unwrap() / 2,
1195            TimeDelta::try_milliseconds(-500).unwrap()
1196        );
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!(TimeDelta::try_seconds(-4).unwrap() / 3, TimeDelta::nanoseconds(-1_333_333_333));
1206        assert_eq!(TimeDelta::try_seconds(-4).unwrap() / -3, TimeDelta::nanoseconds(1_333_333_333));
1207    }
1208
1209    #[test]
1210    fn test_duration_sum() {
1211        let duration_list_1 = [TimeDelta::zero(), TimeDelta::try_seconds(1).unwrap()];
1212        let sum_1: TimeDelta = duration_list_1.iter().sum();
1213        assert_eq!(sum_1, TimeDelta::try_seconds(1).unwrap());
1214
1215        let duration_list_2 = [
1216            TimeDelta::zero(),
1217            TimeDelta::try_seconds(1).unwrap(),
1218            TimeDelta::try_seconds(6).unwrap(),
1219            TimeDelta::try_seconds(10).unwrap(),
1220        ];
1221        let sum_2: TimeDelta = duration_list_2.iter().sum();
1222        assert_eq!(sum_2, TimeDelta::try_seconds(17).unwrap());
1223
1224        let duration_arr = [
1225            TimeDelta::zero(),
1226            TimeDelta::try_seconds(1).unwrap(),
1227            TimeDelta::try_seconds(6).unwrap(),
1228            TimeDelta::try_seconds(10).unwrap(),
1229        ];
1230        let sum_3: TimeDelta = duration_arr.into_iter().sum();
1231        assert_eq!(sum_3, TimeDelta::try_seconds(17).unwrap());
1232    }
1233
1234    #[test]
1235    fn test_duration_fmt() {
1236        assert_eq!(TimeDelta::zero().to_string(), "P0D");
1237        assert_eq!(TimeDelta::try_days(42).unwrap().to_string(), "PT3628800S");
1238        assert_eq!(TimeDelta::try_days(-42).unwrap().to_string(), "-PT3628800S");
1239        assert_eq!(TimeDelta::try_seconds(42).unwrap().to_string(), "PT42S");
1240        assert_eq!(TimeDelta::try_milliseconds(42).unwrap().to_string(), "PT0.042S");
1241        assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S");
1242        assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S");
1243        assert_eq!(
1244            (TimeDelta::try_days(7).unwrap() + TimeDelta::try_milliseconds(6543).unwrap())
1245                .to_string(),
1246            "PT604806.543S"
1247        );
1248        assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().to_string(), "-PT86401S");
1249        assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S");
1250
1251        // the format specifier should have no effect on `TimeDelta`
1252        assert_eq!(
1253            format!(
1254                "{:30}",
1255                TimeDelta::try_days(1).unwrap() + TimeDelta::try_milliseconds(2345).unwrap()
1256            ),
1257            "PT86402.345S"
1258        );
1259    }
1260
1261    #[test]
1262    fn test_to_std() {
1263        assert_eq!(TimeDelta::try_seconds(1).unwrap().to_std(), Ok(Duration::new(1, 0)));
1264        assert_eq!(TimeDelta::try_seconds(86_401).unwrap().to_std(), Ok(Duration::new(86_401, 0)));
1265        assert_eq!(
1266            TimeDelta::try_milliseconds(123).unwrap().to_std(),
1267            Ok(Duration::new(0, 123_000_000))
1268        );
1269        assert_eq!(
1270            TimeDelta::try_milliseconds(123_765).unwrap().to_std(),
1271            Ok(Duration::new(123, 765_000_000))
1272        );
1273        assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777)));
1274        assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000)));
1275        assert_eq!(TimeDelta::try_seconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1276        assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1277    }
1278
1279    #[test]
1280    fn test_from_std() {
1281        assert_eq!(
1282            Ok(TimeDelta::try_seconds(1).unwrap()),
1283            TimeDelta::from_std(Duration::new(1, 0))
1284        );
1285        assert_eq!(
1286            Ok(TimeDelta::try_seconds(86_401).unwrap()),
1287            TimeDelta::from_std(Duration::new(86_401, 0))
1288        );
1289        assert_eq!(
1290            Ok(TimeDelta::try_milliseconds(123).unwrap()),
1291            TimeDelta::from_std(Duration::new(0, 123_000_000))
1292        );
1293        assert_eq!(
1294            Ok(TimeDelta::try_milliseconds(123_765).unwrap()),
1295            TimeDelta::from_std(Duration::new(123, 765_000_000))
1296        );
1297        assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777)));
1298        assert_eq!(Ok(MAX), TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_000)));
1299        assert_eq!(
1300            TimeDelta::from_std(Duration::new(9_223_372_036_854_776, 0)),
1301            Err(OutOfRangeError(()))
1302        );
1303        assert_eq!(
1304            TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_001)),
1305            Err(OutOfRangeError(()))
1306        );
1307    }
1308
1309    #[test]
1310    fn test_duration_const() {
1311        const ONE_WEEK: TimeDelta = expect(TimeDelta::try_weeks(1), "");
1312        const ONE_DAY: TimeDelta = expect(TimeDelta::try_days(1), "");
1313        const ONE_HOUR: TimeDelta = expect(TimeDelta::try_hours(1), "");
1314        const ONE_MINUTE: TimeDelta = expect(TimeDelta::try_minutes(1), "");
1315        const ONE_SECOND: TimeDelta = expect(TimeDelta::try_seconds(1), "");
1316        const ONE_MILLI: TimeDelta = expect(TimeDelta::try_milliseconds(1), "");
1317        const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1);
1318        const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1);
1319        let combo: TimeDelta = ONE_WEEK
1320            + ONE_DAY
1321            + ONE_HOUR
1322            + ONE_MINUTE
1323            + ONE_SECOND
1324            + ONE_MILLI
1325            + ONE_MICRO
1326            + ONE_NANO;
1327
1328        assert!(ONE_WEEK != TimeDelta::zero());
1329        assert!(ONE_DAY != TimeDelta::zero());
1330        assert!(ONE_HOUR != TimeDelta::zero());
1331        assert!(ONE_MINUTE != TimeDelta::zero());
1332        assert!(ONE_SECOND != TimeDelta::zero());
1333        assert!(ONE_MILLI != TimeDelta::zero());
1334        assert!(ONE_MICRO != TimeDelta::zero());
1335        assert!(ONE_NANO != TimeDelta::zero());
1336        assert_eq!(
1337            combo,
1338            TimeDelta::try_seconds(86400 * 7 + 86400 + 3600 + 60 + 1).unwrap()
1339                + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000)
1340        );
1341    }
1342
1343    #[test]
1344    #[cfg(feature = "rkyv-validation")]
1345    fn test_rkyv_validation() {
1346        let duration = TimeDelta::try_seconds(1).unwrap();
1347        let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
1348        assert_eq!(rkyv::from_bytes::<TimeDelta>(&bytes).unwrap(), duration);
1349    }
1350}