• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 use core::fmt;
14 use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
15 use core::time::Duration;
16 #[cfg(feature = "std")]
17 use std::error::Error;
18 
19 use crate::{expect, try_opt};
20 
21 #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
22 use rkyv::{Archive, Deserialize, Serialize};
23 
24 /// The number of nanoseconds in a microsecond.
25 const NANOS_PER_MICRO: i32 = 1000;
26 /// The number of nanoseconds in a millisecond.
27 const NANOS_PER_MILLI: i32 = 1_000_000;
28 /// The number of nanoseconds in seconds.
29 pub(crate) const NANOS_PER_SEC: i32 = 1_000_000_000;
30 /// The number of microseconds per second.
31 const MICROS_PER_SEC: i64 = 1_000_000;
32 /// The number of milliseconds per second.
33 const MILLIS_PER_SEC: i64 = 1000;
34 /// The number of seconds in a minute.
35 const SECS_PER_MINUTE: i64 = 60;
36 /// The number of seconds in an hour.
37 const SECS_PER_HOUR: i64 = 3600;
38 /// The number of (non-leap) seconds in days.
39 const SECS_PER_DAY: i64 = 86_400;
40 /// The number of (non-leap) seconds in a week.
41 const 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))]
60 pub struct TimeDelta {
61     secs: i64,
62     nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
63 }
64 
65 /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
66 pub(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.
72 pub(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 
77 impl 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.
new(secs: i64, nanos: u32) -> Option<TimeDelta>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]
weeks(weeks: i64) -> TimeDelta105     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]
try_weeks(weeks: i64) -> Option<TimeDelta>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]
days(days: i64) -> TimeDelta132     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]
try_days(days: i64) -> Option<TimeDelta>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]
hours(hours: i64) -> TimeDelta158     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]
try_hours(hours: i64) -> Option<TimeDelta>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]
minutes(minutes: i64) -> TimeDelta183     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]
try_minutes(minutes: i64) -> Option<TimeDelta>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]
seconds(seconds: i64) -> TimeDelta207     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]
try_seconds(seconds: i64) -> Option<TimeDelta>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]
milliseconds(milliseconds: i64) -> TimeDelta230     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]
try_milliseconds(milliseconds: i64) -> Option<TimeDelta>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]
microseconds(microseconds: i64) -> TimeDelta259     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]
nanoseconds(nanos: i64) -> TimeDelta272     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]
num_weeks(&self) -> i64279     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]
num_days(&self) -> i64285     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]
num_hours(&self) -> i64291     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]
num_minutes(&self) -> i64297     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`.
num_seconds(&self) -> i64302     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`.
subsec_nanos(&self) -> i32314     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`.
num_milliseconds(&self) -> i64323     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).
num_microseconds(&self) -> Option<i64>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).
num_nanoseconds(&self) -> Option<i64>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]
checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta>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]
checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta>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]
checked_mul(&self, rhs: i32) -> Option<TimeDelta>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]
checked_div(&self, rhs: i32) -> Option<TimeDelta>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]
abs(&self) -> TimeDelta412     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]
min_value() -> TimeDelta423     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]
max_value() -> TimeDelta430     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]
zero() -> TimeDelta436     pub const fn zero() -> TimeDelta {
437         TimeDelta { secs: 0, nanos: 0 }
438     }
439 
440     /// Returns `true` if the `TimeDelta` equals `TimeDelta::zero()`.
441     #[inline]
is_zero(&self) -> bool442     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.
from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError>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.
to_std(&self) -> Result<Duration, OutOfRangeError>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.
neg(self) -> TimeDelta473     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 
488 impl Neg for TimeDelta {
489     type Output = TimeDelta;
490 
491     #[inline]
neg(self) -> TimeDelta492     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 
501 impl Add for TimeDelta {
502     type Output = TimeDelta;
503 
add(self, rhs: TimeDelta) -> TimeDelta504     fn add(self, rhs: TimeDelta) -> TimeDelta {
505         self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed")
506     }
507 }
508 
509 impl Sub for TimeDelta {
510     type Output = TimeDelta;
511 
sub(self, rhs: TimeDelta) -> TimeDelta512     fn sub(self, rhs: TimeDelta) -> TimeDelta {
513         self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed")
514     }
515 }
516 
517 impl AddAssign for TimeDelta {
add_assign(&mut self, rhs: 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 
524 impl SubAssign for TimeDelta {
sub_assign(&mut self, rhs: 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 
531 impl Mul<i32> for TimeDelta {
532     type Output = TimeDelta;
533 
mul(self, rhs: i32) -> TimeDelta534     fn mul(self, rhs: i32) -> TimeDelta {
535         self.checked_mul(rhs).expect("`TimeDelta * i32` overflowed")
536     }
537 }
538 
539 impl Div<i32> for TimeDelta {
540     type Output = TimeDelta;
541 
div(self, rhs: i32) -> TimeDelta542     fn div(self, rhs: i32) -> TimeDelta {
543         self.checked_div(rhs).expect("`i32` is zero")
544     }
545 }
546 
547 impl<'a> core::iter::Sum<&'a TimeDelta> for TimeDelta {
sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta548     fn sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta {
549         iter.fold(TimeDelta::zero(), |acc, x| acc + *x)
550     }
551 }
552 
553 impl core::iter::Sum<TimeDelta> for TimeDelta {
sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta554     fn sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta {
555         iter.fold(TimeDelta::zero(), |acc, x| acc + x)
556     }
557 }
558 
559 impl 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
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result563     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)]
603 pub struct OutOfRangeError(());
604 
605 impl fmt::Display for OutOfRangeError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result606     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")]
612 impl Error for OutOfRangeError {
613     #[allow(deprecated)]
description(&self) -> &str614     fn description(&self) -> &str {
615         "out of range error"
616     }
617 }
618 
619 #[inline]
div_mod_floor_64(this: i64, other: i64) -> (i64, i64)620 const 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"))]
625 impl arbitrary::Arbitrary<'_> for TimeDelta {
arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<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")]
643 mod serde {
644     use super::TimeDelta;
645     use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
646 
647     impl Serialize for TimeDelta {
serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>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 {
deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>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]
test_serde()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")]
test_serde_oob_panic()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)]
684 mod tests {
685     use super::OutOfRangeError;
686     use super::{TimeDelta, MAX, MIN};
687     use crate::expect;
688     use core::time::Duration;
689 
690     #[test]
test_duration()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]
test_duration_num_days()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]
test_duration_num_seconds()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]
test_duration_seconds_max_allowed()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]
test_duration_seconds_max_overflow()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")]
test_duration_seconds_max_overflow_panic()754     fn test_duration_seconds_max_overflow_panic() {
755         let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
756     }
757 
758     #[test]
test_duration_seconds_min_allowed()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]
test_duration_seconds_min_underflow()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")]
test_duration_seconds_min_underflow_panic()775     fn test_duration_seconds_min_underflow_panic() {
776         let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1);
777     }
778 
779     #[test]
test_duration_num_milliseconds()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]
test_duration_milliseconds_max_allowed()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]
test_duration_milliseconds_max_overflow()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]
test_duration_milliseconds_min_allowed()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]
test_duration_milliseconds_min_underflow()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")]
test_duration_milliseconds_min_underflow_panic()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]
test_duration_num_microseconds()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]
test_duration_microseconds_max_allowed()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]
test_duration_microseconds_max_overflow()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]
test_duration_microseconds_min_allowed()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]
test_duration_microseconds_min_underflow()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]
test_duration_num_nanoseconds()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]
test_duration_nanoseconds_max_allowed()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]
test_duration_nanoseconds_max_overflow()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]
test_duration_nanoseconds_min_allowed()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]
test_duration_nanoseconds_min_underflow()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]
test_max()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]
test_min()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]
test_duration_ord()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]
test_duration_checked_ops()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]
test_duration_abs()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)]
test_duration_mul()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]
test_duration_div()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]
test_duration_sum()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]
test_duration_fmt()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]
test_to_std()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]
test_from_std()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]
test_duration_const()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")]
test_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 }
1351