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.
1011//! Temporal quantification
1213#[cfg(all(not(feature = "std"), feature = "core-error"))]
14use core::error::Error;
15use core::fmt;
16use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
17use core::time::Duration;
18#[cfg(feature = "std")]
19use std::error::Error;
2021use crate::{expect, try_opt};
2223#[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
24use rkyv::{Archive, Deserialize, Serialize};
2526/// The number of nanoseconds in a microsecond.
27const NANOS_PER_MICRO: i32 = 1000;
28/// The number of nanoseconds in a millisecond.
29const NANOS_PER_MILLI: i32 = 1_000_000;
30/// The number of nanoseconds in seconds.
31pub(crate) const NANOS_PER_SEC: i32 = 1_000_000_000;
32/// The number of microseconds per second.
33const MICROS_PER_SEC: i64 = 1_000_000;
34/// The number of milliseconds per second.
35const MILLIS_PER_SEC: i64 = 1000;
36/// The number of seconds in a minute.
37const SECS_PER_MINUTE: i64 = 60;
38/// The number of seconds in an hour.
39const SECS_PER_HOUR: i64 = 3600;
40/// The number of (non-leap) seconds in days.
41const SECS_PER_DAY: i64 = 86_400;
42/// The number of (non-leap) seconds in a week.
43const SECS_PER_WEEK: i64 = 604_800;
4445/// Time duration with nanosecond precision.
46///
47/// This also allows for negative durations; see individual methods for details.
48///
49/// A `TimeDelta` is represented internally as a complement of seconds and
50/// nanoseconds. The range is restricted to that of `i64` milliseconds, with the
51/// minimum value notably being set to `-i64::MAX` rather than allowing the full
52/// range of `i64::MIN`. This is to allow easy flipping of sign, so that for
53/// instance `abs()` can be called without any checks.
54#[derive(#[automatically_derived]
impl ::core::clone::Clone for TimeDelta {
#[inline]
fn clone(&self) -> TimeDelta {
let _: ::core::clone::AssertParamIsClone<i64>;
let _: ::core::clone::AssertParamIsClone<i32>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for TimeDelta { }Copy, #[automatically_derived]
impl ::core::default::Default for TimeDelta {
#[inline]
fn default() -> TimeDelta {
TimeDelta {
secs: ::core::default::Default::default(),
nanos: ::core::default::Default::default(),
}
}
}Default, #[automatically_derived]
impl ::core::cmp::PartialEq for TimeDelta {
#[inline]
fn eq(&self, other: &TimeDelta) -> bool {
self.secs == other.secs && self.nanos == other.nanos
}
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for TimeDelta {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<i64>;
let _: ::core::cmp::AssertParamIsEq<i32>;
}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialOrd for TimeDelta {
#[inline]
fn partial_cmp(&self, other: &TimeDelta)
-> ::core::option::Option<::core::cmp::Ordering> {
match ::core::cmp::PartialOrd::partial_cmp(&self.secs, &other.secs) {
::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
::core::cmp::PartialOrd::partial_cmp(&self.nanos,
&other.nanos),
cmp => cmp,
}
}
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for TimeDelta {
#[inline]
fn cmp(&self, other: &TimeDelta) -> ::core::cmp::Ordering {
match ::core::cmp::Ord::cmp(&self.secs, &other.secs) {
::core::cmp::Ordering::Equal =>
::core::cmp::Ord::cmp(&self.nanos, &other.nanos),
cmp => cmp,
}
}
}Ord, #[automatically_derived]
impl ::core::fmt::Debug for TimeDelta {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f, "TimeDelta",
"secs", &self.secs, "nanos", &&self.nanos)
}
}Debug, #[automatically_derived]
impl ::core::hash::Hash for TimeDelta {
#[inline]
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
::core::hash::Hash::hash(&self.secs, state);
::core::hash::Hash::hash(&self.nanos, state)
}
}Hash)]
55#[cfg_attr(
56 any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
57 derive(Archive, Deserialize, Serialize),
58 archive(compare(PartialEq, PartialOrd)),
59 archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
60)]
61#[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
62#[cfg_attr(feature = "defmt", derive(defmt::Format))]
63pub struct TimeDelta {
64 secs: i64,
65 nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
66}
6768/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
69pub(crate) const MIN: TimeDelta = TimeDelta {
70 secs: -i64::MAX / MILLIS_PER_SEC - 1,
71 nanos: NANOS_PER_SEC + (-i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
72};
7374/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
75pub(crate) const MAX: TimeDelta = TimeDelta {
76 secs: i64::MAX / MILLIS_PER_SEC,
77 nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
78};
7980impl TimeDelta {
81/// Makes a new `TimeDelta` with given number of seconds and nanoseconds.
82 ///
83 /// # Errors
84 ///
85 /// Returns `None` when the duration is out of bounds, or if `nanos` ≥ 1,000,000,000.
86pub const fn new(secs: i64, nanos: u32) -> Option<TimeDelta> {
87if secs < MIN.secs
88 || secs > MAX.secs
89 || nanos >= 1_000_000_000
90|| (secs == MAX.secs && nanos > MAX.nanos as u32)
91 || (secs == MIN.secs && nanos < MIN.nanos as u32)
92 {
93return None;
94 }
95Some(TimeDelta { secs, nanos: nanosas i32 })
96 }
9798/// Makes a new `TimeDelta` with the given number of weeks.
99 ///
100 /// Equivalent to `TimeDelta::seconds(weeks * 7 * 24 * 60 * 60)` with
101 /// overflow checks.
102 ///
103 /// # Panics
104 ///
105 /// Panics when the duration is out of bounds.
106#[inline]
107 #[must_use]
108pub const fn weeks(weeks: i64) -> TimeDelta {
109expect(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds")
110 }
111112/// Makes a new `TimeDelta` with the given number of weeks.
113 ///
114 /// Equivalent to `TimeDelta::try_seconds(weeks * 7 * 24 * 60 * 60)` with
115 /// overflow checks.
116 ///
117 /// # Errors
118 ///
119 /// Returns `None` when the `TimeDelta` would be out of bounds.
120#[inline]
121pub const fn try_weeks(weeks: i64) -> Option<TimeDelta> {
122TimeDelta::try_seconds(match weeks.checked_mul(SECS_PER_WEEK) { Some(v) => v, None => return None, }try_opt!(weeks.checked_mul(SECS_PER_WEEK)))
123 }
124125/// Makes a new `TimeDelta` with the given number of days.
126 ///
127 /// Equivalent to `TimeDelta::seconds(days * 24 * 60 * 60)` with overflow
128 /// checks.
129 ///
130 /// # Panics
131 ///
132 /// Panics when the `TimeDelta` would be out of bounds.
133#[inline]
134 #[must_use]
135pub const fn days(days: i64) -> TimeDelta {
136expect(TimeDelta::try_days(days), "TimeDelta::days out of bounds")
137 }
138139/// Makes a new `TimeDelta` with the given number of days.
140 ///
141 /// Equivalent to `TimeDelta::try_seconds(days * 24 * 60 * 60)` with overflow
142 /// checks.
143 ///
144 /// # Errors
145 ///
146 /// Returns `None` when the `TimeDelta` would be out of bounds.
147#[inline]
148pub const fn try_days(days: i64) -> Option<TimeDelta> {
149TimeDelta::try_seconds(match days.checked_mul(SECS_PER_DAY) { Some(v) => v, None => return None, }try_opt!(days.checked_mul(SECS_PER_DAY)))
150 }
151152/// Makes a new `TimeDelta` with the given number of hours.
153 ///
154 /// Equivalent to `TimeDelta::seconds(hours * 60 * 60)` with overflow checks.
155 ///
156 /// # Panics
157 ///
158 /// Panics when the `TimeDelta` would be out of bounds.
159#[inline]
160 #[must_use]
161pub const fn hours(hours: i64) -> TimeDelta {
162expect(TimeDelta::try_hours(hours), "TimeDelta::hours out of bounds")
163 }
164165/// Makes a new `TimeDelta` with the given number of hours.
166 ///
167 /// Equivalent to `TimeDelta::try_seconds(hours * 60 * 60)` with overflow checks.
168 ///
169 /// # Errors
170 ///
171 /// Returns `None` when the `TimeDelta` would be out of bounds.
172#[inline]
173pub const fn try_hours(hours: i64) -> Option<TimeDelta> {
174TimeDelta::try_seconds(match hours.checked_mul(SECS_PER_HOUR) { Some(v) => v, None => return None, }try_opt!(hours.checked_mul(SECS_PER_HOUR)))
175 }
176177/// Makes a new `TimeDelta` with the given number of minutes.
178 ///
179 /// Equivalent to `TimeDelta::seconds(minutes * 60)` with overflow checks.
180 ///
181 /// # Panics
182 ///
183 /// Panics when the `TimeDelta` would be out of bounds.
184#[inline]
185 #[must_use]
186pub const fn minutes(minutes: i64) -> TimeDelta {
187expect(TimeDelta::try_minutes(minutes), "TimeDelta::minutes out of bounds")
188 }
189190/// Makes a new `TimeDelta` with the given number of minutes.
191 ///
192 /// Equivalent to `TimeDelta::try_seconds(minutes * 60)` with overflow checks.
193 ///
194 /// # Errors
195 ///
196 /// Returns `None` when the `TimeDelta` would be out of bounds.
197#[inline]
198pub const fn try_minutes(minutes: i64) -> Option<TimeDelta> {
199TimeDelta::try_seconds(match minutes.checked_mul(SECS_PER_MINUTE) {
Some(v) => v,
None => return None,
}try_opt!(minutes.checked_mul(SECS_PER_MINUTE)))
200 }
201202/// Makes a new `TimeDelta` with the given number of seconds.
203 ///
204 /// # Panics
205 ///
206 /// Panics when `seconds` is more than `i64::MAX / 1_000` or less than `-i64::MAX / 1_000`
207 /// (in this context, this is the same as `i64::MIN / 1_000` due to rounding).
208#[inline]
209 #[must_use]
210pub const fn seconds(seconds: i64) -> TimeDelta {
211expect(TimeDelta::try_seconds(seconds), "TimeDelta::seconds out of bounds")
212 }
213214/// Makes a new `TimeDelta` with the given number of seconds.
215 ///
216 /// # Errors
217 ///
218 /// Returns `None` when `seconds` is more than `i64::MAX / 1_000` or less than
219 /// `-i64::MAX / 1_000` (in this context, this is the same as `i64::MIN / 1_000` due to
220 /// rounding).
221#[inline]
222pub const fn try_seconds(seconds: i64) -> Option<TimeDelta> {
223TimeDelta::new(seconds, 0)
224 }
225226/// Makes a new `TimeDelta` with the given number of milliseconds.
227 ///
228 /// # Panics
229 ///
230 /// Panics when the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more than
231 /// `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
232#[inline]
233pub const fn milliseconds(milliseconds: i64) -> TimeDelta {
234expect(TimeDelta::try_milliseconds(milliseconds), "TimeDelta::milliseconds out of bounds")
235 }
236237/// Makes a new `TimeDelta` with the given number of milliseconds.
238 ///
239 /// # Errors
240 ///
241 /// Returns `None` the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more
242 /// than `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
243#[inline]
244pub const fn try_milliseconds(milliseconds: i64) -> Option<TimeDelta> {
245// We don't need to compare against MAX, as this function accepts an
246 // i64, and MAX is aligned to i64::MAX milliseconds.
247if milliseconds < -i64::MAX {
248return None;
249 }
250let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
251let d = TimeDelta { secs, nanos: millisas i32 * NANOS_PER_MILLI };
252Some(d)
253 }
254255/// Makes a new `TimeDelta` with the given number of microseconds.
256 ///
257 /// The number of microseconds acceptable by this constructor is less than
258 /// the total number that can actually be stored in a `TimeDelta`, so it is
259 /// not possible to specify a value that would be out of bounds. This
260 /// function is therefore infallible.
261#[inline]
262pub const fn microseconds(microseconds: i64) -> TimeDelta {
263let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
264let nanos = microsas i32 * NANOS_PER_MICRO;
265TimeDelta { secs, nanos }
266 }
267268/// Makes a new `TimeDelta` with the given number of nanoseconds.
269 ///
270 /// The number of nanoseconds acceptable by this constructor is less than
271 /// the total number that can actually be stored in a `TimeDelta`, so it is
272 /// not possible to specify a value that would be out of bounds. This
273 /// function is therefore infallible.
274#[inline]
275pub const fn nanoseconds(nanos: i64) -> TimeDelta {
276let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SECas i64);
277TimeDelta { secs, nanos: nanosas i32 }
278 }
279280/// Returns the total number of whole weeks in the `TimeDelta`.
281#[inline]
282pub const fn num_weeks(&self) -> i64 {
283self.num_days() / 7
284}
285286/// Returns the total number of whole days in the `TimeDelta`.
287#[inline]
288pub const fn num_days(&self) -> i64 {
289self.num_seconds() / SECS_PER_DAY290 }
291292/// Returns the total number of whole hours in the `TimeDelta`.
293#[inline]
294pub const fn num_hours(&self) -> i64 {
295self.num_seconds() / SECS_PER_HOUR296 }
297298/// Returns the total number of whole minutes in the `TimeDelta`.
299#[inline]
300pub const fn num_minutes(&self) -> i64 {
301self.num_seconds() / SECS_PER_MINUTE302 }
303304/// Returns the total number of whole seconds in the `TimeDelta`.
305pub const fn num_seconds(&self) -> i64 {
306// If secs is negative, nanos should be subtracted from the duration.
307if self.secs < 0 && self.nanos > 0 { self.secs + 1 } else { self.secs }
308 }
309310/// Returns the fractional number of seconds in the `TimeDelta`.
311pub fn as_seconds_f64(self) -> f64 {
312self.secs as f64 + self.nanos as f64 / NANOS_PER_SECas f64313 }
314315/// Returns the fractional number of seconds in the `TimeDelta`.
316pub fn as_seconds_f32(self) -> f32 {
317self.secs as f32 + self.nanos as f32 / NANOS_PER_SECas f32318 }
319320/// Returns the total number of whole milliseconds in the `TimeDelta`.
321pub const fn num_milliseconds(&self) -> i64 {
322// A proper TimeDelta will not overflow, because MIN and MAX are defined such
323 // that the range is within the bounds of an i64, from -i64::MAX through to
324 // +i64::MAX inclusive. Notably, i64::MIN is excluded from this range.
325let secs_part = self.num_seconds() * MILLIS_PER_SEC;
326let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI;
327secs_part + nanos_partas i64328 }
329330/// Returns the number of milliseconds in the fractional part of the duration.
331 ///
332 /// This is the number of milliseconds such that
333 /// `subsec_millis() + num_seconds() * 1_000` is the truncated number of
334 /// milliseconds in the duration.
335pub const fn subsec_millis(&self) -> i32 {
336self.subsec_nanos() / NANOS_PER_MILLI337 }
338339/// Returns the total number of whole microseconds in the `TimeDelta`,
340 /// or `None` on overflow (exceeding 2^63 microseconds in either direction).
341pub const fn num_microseconds(&self) -> Option<i64> {
342let secs_part = match self.num_seconds().checked_mul(MICROS_PER_SEC) {
Some(v) => v,
None => return None,
}try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
343let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO;
344secs_part.checked_add(nanos_partas i64)
345 }
346347/// Returns the number of microseconds in the fractional part of the duration.
348 ///
349 /// This is the number of microseconds such that
350 /// `subsec_micros() + num_seconds() * 1_000_000` is the truncated number of
351 /// microseconds in the duration.
352pub const fn subsec_micros(&self) -> i32 {
353self.subsec_nanos() / NANOS_PER_MICRO354 }
355356/// Returns the total number of whole nanoseconds in the `TimeDelta`,
357 /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
358pub const fn num_nanoseconds(&self) -> Option<i64> {
359let secs_part = match self.num_seconds().checked_mul(NANOS_PER_SEC as i64) {
Some(v) => v,
None => return None,
}try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
360let nanos_part = self.subsec_nanos();
361secs_part.checked_add(nanos_partas i64)
362 }
363364/// Returns the number of nanoseconds in the fractional part of the duration.
365 ///
366 /// This is the number of nanoseconds such that
367 /// `subsec_nanos() + num_seconds() * 1_000_000_000` is the total number of
368 /// nanoseconds in the `TimeDelta`.
369pub const fn subsec_nanos(&self) -> i32 {
370if self.secs < 0 && self.nanos > 0 { self.nanos - NANOS_PER_SEC } else { self.nanos }
371 }
372373/// Add two `TimeDelta`s, returning `None` if overflow occurred.
374#[must_use]
375pub const fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
376// No overflow checks here because we stay comfortably within the range of an `i64`.
377 // Range checks happen in `TimeDelta::new`.
378let mut secs = self.secs + rhs.secs;
379let mut nanos = self.nanos + rhs.nanos;
380if nanos >= NANOS_PER_SEC {
381nanos -= NANOS_PER_SEC;
382secs += 1;
383 }
384TimeDelta::new(secs, nanosas u32)
385 }
386387/// Subtract two `TimeDelta`s, returning `None` if overflow occurred.
388#[must_use]
389pub const fn checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
390// No overflow checks here because we stay comfortably within the range of an `i64`.
391 // Range checks happen in `TimeDelta::new`.
392let mut secs = self.secs - rhs.secs;
393let mut nanos = self.nanos - rhs.nanos;
394if nanos < 0 {
395nanos += NANOS_PER_SEC;
396secs -= 1;
397 }
398TimeDelta::new(secs, nanosas u32)
399 }
400401/// Multiply a `TimeDelta` with a i32, returning `None` if overflow occurred.
402#[must_use]
403pub const fn checked_mul(&self, rhs: i32) -> Option<TimeDelta> {
404// Multiply nanoseconds as i64, because it cannot overflow that way.
405let total_nanos = self.nanos as i64 * rhsas i64;
406let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SECas i64);
407// Multiply seconds as i128 to prevent overflow
408let secs: i128 = self.secs as i128 * rhsas i128 + extra_secsas i128;
409if secs <= i64::MINas i128 || secs >= i64::MAXas i128 {
410return None;
411 };
412Some(TimeDelta { secs: secsas i64, nanos: nanosas i32 })
413 }
414415/// Divide a `TimeDelta` with a i32, returning `None` if dividing by 0.
416#[must_use]
417pub const fn checked_div(&self, rhs: i32) -> Option<TimeDelta> {
418if rhs == 0 {
419return None;
420 }
421let secs = self.secs / rhsas i64;
422let carry = self.secs % rhsas i64;
423let extra_nanos = carry * NANOS_PER_SECas i64 / rhsas i64;
424let nanos = self.nanos / rhs + extra_nanosas i32;
425426let (secs, nanos) = match nanos {
427i32::MIN..=-1 => (secs - 1, nanos + NANOS_PER_SEC),
428NANOS_PER_SEC..=i32::MAX => (secs + 1, nanos - NANOS_PER_SEC),
429_ => (secs, nanos),
430 };
431432Some(TimeDelta { secs, nanos })
433 }
434435/// Returns the `TimeDelta` as an absolute (non-negative) value.
436#[inline]
437pub const fn abs(&self) -> TimeDelta {
438if self.secs < 0 && self.nanos != 0 {
439TimeDelta { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos }
440 } else {
441TimeDelta { secs: self.secs.abs(), nanos: self.nanos }
442 }
443 }
444445/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
446#[deprecated(since = "0.4.39", note = "Use `TimeDelta::MIN` instead")]
447 #[inline]
448pub const fn min_value() -> TimeDelta {
449MIN450 }
451452/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
453#[deprecated(since = "0.4.39", note = "Use `TimeDelta::MAX` instead")]
454 #[inline]
455pub const fn max_value() -> TimeDelta {
456MAX457 }
458459/// A `TimeDelta` where the stored seconds and nanoseconds are equal to zero.
460#[inline]
461pub const fn zero() -> TimeDelta {
462TimeDelta { secs: 0, nanos: 0 }
463 }
464465/// Returns `true` if the `TimeDelta` equals `TimeDelta::zero()`.
466#[inline]
467pub const fn is_zero(&self) -> bool {
468self.secs == 0 && self.nanos == 0
469}
470471/// Creates a `TimeDelta` object from `std::time::Duration`
472 ///
473 /// This function errors when original duration is larger than the maximum
474 /// value supported for this type.
475pub const fn from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError> {
476// We need to check secs as u64 before coercing to i64
477if duration.as_secs() > MAX.secs as u64 {
478return Err(OutOfRangeError(()));
479 }
480match TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos()) {
481Some(d) => Ok(d),
482None => Err(OutOfRangeError(())),
483 }
484 }
485486/// Creates a `std::time::Duration` object from a `TimeDelta`.
487 ///
488 /// This function errors when duration is less than zero. As standard
489 /// library implementation is limited to non-negative values.
490pub const fn to_std(&self) -> Result<Duration, OutOfRangeError> {
491if self.secs < 0 {
492return Err(OutOfRangeError(()));
493 }
494Ok(Duration::new(self.secs as u64, self.nanos as u32))
495 }
496497/// This duplicates `Neg::neg` because trait methods can't be const yet.
498pub(crate) const fn neg(self) -> TimeDelta {
499let (secs_diff, nanos) = match self.nanos {
5000 => (0, 0),
501 nanos => (1, NANOS_PER_SEC - nanos),
502 };
503TimeDelta { secs: -self.secs - secs_diff, nanos }
504 }
505506/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
507pub const MIN: Self = MIN;
508509/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
510pub const MAX: Self = MAX;
511}
512513impl Negfor TimeDelta {
514type Output = TimeDelta;
515516#[inline]
517fn neg(self) -> TimeDelta {
518let (secs_diff, nanos) = match self.nanos {
5190 => (0, 0),
520 nanos => (1, NANOS_PER_SEC - nanos),
521 };
522TimeDelta { secs: -self.secs - secs_diff, nanos }
523 }
524}
525526impl Addfor TimeDelta {
527type Output = TimeDelta;
528529fn add(self, rhs: TimeDelta) -> TimeDelta {
530self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed")
531 }
532}
533534impl Subfor TimeDelta {
535type Output = TimeDelta;
536537fn sub(self, rhs: TimeDelta) -> TimeDelta {
538self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed")
539 }
540}
541542impl AddAssignfor TimeDelta {
543fn add_assign(&mut self, rhs: TimeDelta) {
544let new = self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed");
545*self = new;
546 }
547}
548549impl SubAssignfor TimeDelta {
550fn sub_assign(&mut self, rhs: TimeDelta) {
551let new = self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed");
552*self = new;
553 }
554}
555556impl Mul<i32> for TimeDelta {
557type Output = TimeDelta;
558559fn mul(self, rhs: i32) -> TimeDelta {
560self.checked_mul(rhs).expect("`TimeDelta * i32` overflowed")
561 }
562}
563564impl Div<i32> for TimeDelta {
565type Output = TimeDelta;
566567fn div(self, rhs: i32) -> TimeDelta {
568self.checked_div(rhs).expect("`i32` is zero")
569 }
570}
571572impl<'a> core::iter::Sum<&'a TimeDelta> for TimeDelta {
573fn sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta {
574iter.fold(TimeDelta::zero(), |acc, x| acc + *x)
575 }
576}
577578impl core::iter::Sum<TimeDelta> for TimeDelta {
579fn sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta {
580iter.fold(TimeDelta::zero(), |acc, x| acc + x)
581 }
582}
583584impl fmt::Displayfor TimeDelta {
585/// Format a `TimeDelta` using the [ISO 8601] format
586 ///
587 /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601#Durations
588fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
589// technically speaking, negative duration is not valid ISO 8601,
590 // but we need to print it anyway.
591let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
592593f.write_fmt(format_args!("{0}P", sign))write!(f, "{sign}P")?;
594// Plenty of ways to encode an empty string. `P0D` is short and not too strange.
595if abs.secs == 0 && abs.nanos == 0 {
596return f.write_str("0D");
597 }
598599f.write_fmt(format_args!("T{0}", abs.secs)format_args!("T{}", abs.secs))?;
600601if abs.nanos > 0 {
602// Count the number of significant digits, while removing all trailing zero's.
603let mut figures = 9usize;
604let mut fraction_digits = abs.nanos;
605loop {
606let div = fraction_digits / 10;
607let last_digit = fraction_digits % 10;
608if last_digit != 0 {
609break;
610 }
611fraction_digits = div;
612figures -= 1;
613 }
614f.write_fmt(format_args!(".{0:01$}", fraction_digits, figures)format_args!(".{fraction_digits:0figures$}"))?;
615 }
616f.write_str("S")?;
617Ok(())
618 }
619}
620621/// Represents error when converting `TimeDelta` to/from a standard library
622/// implementation
623///
624/// The `std::time::Duration` supports a range from zero to `u64::MAX`
625/// *seconds*, while this module supports signed range of up to
626/// `i64::MAX` of *milliseconds*.
627#[derive(#[automatically_derived]
impl ::core::fmt::Debug for OutOfRangeError {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"OutOfRangeError", &&self.0)
}
}Debug, #[automatically_derived]
impl ::core::clone::Clone for OutOfRangeError {
#[inline]
fn clone(&self) -> OutOfRangeError {
let _: ::core::clone::AssertParamIsClone<()>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for OutOfRangeError { }Copy, #[automatically_derived]
impl ::core::cmp::PartialEq for OutOfRangeError {
#[inline]
fn eq(&self, other: &OutOfRangeError) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for OutOfRangeError {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_receiver_is_total_eq(&self) {
let _: ::core::cmp::AssertParamIsEq<()>;
}
}Eq)]
628#[cfg_attr(feature = "defmt", derive(defmt::Format))]
629pub struct OutOfRangeError(());
630631impl fmt::Displayfor OutOfRangeError {
632fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
633f.write_fmt(format_args!("Source duration value is out of range for the target type"))write!(f, "Source duration value is out of range for the target type")634 }
635}
636637#[cfg(any(feature = "std", feature = "core-error"))]
638impl Errorfor OutOfRangeError {
639#[allow(deprecated)]
640fn description(&self) -> &str {
641"out of range error"
642}
643}
644645#[inline]
646const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
647 (this.div_euclid(other), this.rem_euclid(other))
648}
649650#[cfg(all(feature = "arbitrary", feature = "std"))]
651impl arbitrary::Arbitrary<'_> for TimeDelta {
652fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta> {
653const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1;
654const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
655656let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
657let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?;
658let duration = TimeDelta { secs, nanos };
659660if duration < MIN || duration > MAX {
661Err(arbitrary::Error::IncorrectFormat)
662 } else {
663Ok(duration)
664 }
665 }
666}
667668#[cfg(feature = "serde")]
669mod serde {
670use super::TimeDelta;
671use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
672673impl Serialize for TimeDelta {
674fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
675 <(i64, i32) as Serialize>::serialize(&(self.secs, self.nanos), serializer)
676 }
677 }
678679impl<'de> Deserialize<'de> for TimeDelta {
680fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
681let (secs, nanos) = <(i64, i32) as Deserialize>::deserialize(deserializer)?;
682 TimeDelta::new(secs, nanos as u32).ok_or(Error::custom("TimeDelta out of bounds"))
683 }
684 }
685686#[cfg(test)]
687mod tests {
688use super::{super::MAX, TimeDelta};
689690#[test]
691fn test_serde() {
692let duration = TimeDelta::new(123, 456).unwrap();
693assert_eq!(
694 serde_json::from_value::<TimeDelta>(serde_json::to_value(duration).unwrap())
695 .unwrap(),
696 duration
697 );
698 }
699700#[test]
701 #[should_panic(expected = "TimeDelta out of bounds")]
702fn test_serde_oob_panic() {
703let _ =
704 serde_json::from_value::<TimeDelta>(serde_json::json!([MAX.secs + 1, 0])).unwrap();
705 }
706 }
707}
708709#[cfg(test)]
710mod tests {
711use super::OutOfRangeError;
712use super::{MAX, MIN, TimeDelta};
713use crate::expect;
714use core::time::Duration;
715716#[test]
717fn test_duration() {
718let days = |d| TimeDelta::try_days(d).unwrap();
719let seconds = |s| TimeDelta::try_seconds(s).unwrap();
720721assert!(seconds(1) != TimeDelta::zero());
722assert_eq!(seconds(1) + seconds(2), seconds(3));
723assert_eq!(seconds(86_399) + seconds(4), days(1) + seconds(3));
724assert_eq!(days(10) - seconds(1000), seconds(863_000));
725assert_eq!(days(10) - seconds(1_000_000), seconds(-136_000));
726assert_eq!(
727 days(2) + seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
728 days(3) + TimeDelta::nanoseconds(234_567_890)
729 );
730assert_eq!(-days(3), days(-3));
731assert_eq!(-(days(3) + seconds(70)), days(-4) + seconds(86_400 - 70));
732733let mut d = TimeDelta::default();
734 d += TimeDelta::try_minutes(1).unwrap();
735 d -= seconds(30);
736assert_eq!(d, seconds(30));
737 }
738739#[test]
740fn test_duration_num_days() {
741assert_eq!(TimeDelta::zero().num_days(), 0);
742assert_eq!(TimeDelta::try_days(1).unwrap().num_days(), 1);
743assert_eq!(TimeDelta::try_days(-1).unwrap().num_days(), -1);
744assert_eq!(TimeDelta::try_seconds(86_399).unwrap().num_days(), 0);
745assert_eq!(TimeDelta::try_seconds(86_401).unwrap().num_days(), 1);
746assert_eq!(TimeDelta::try_seconds(-86_399).unwrap().num_days(), 0);
747assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().num_days(), -1);
748assert_eq!(TimeDelta::try_days(i32::MAX as i64).unwrap().num_days(), i32::MAX as i64);
749assert_eq!(TimeDelta::try_days(i32::MIN as i64).unwrap().num_days(), i32::MIN as i64);
750 }
751752#[test]
753fn test_duration_num_seconds() {
754assert_eq!(TimeDelta::zero().num_seconds(), 0);
755assert_eq!(TimeDelta::try_seconds(1).unwrap().num_seconds(), 1);
756assert_eq!(TimeDelta::try_seconds(-1).unwrap().num_seconds(), -1);
757assert_eq!(TimeDelta::try_milliseconds(999).unwrap().num_seconds(), 0);
758assert_eq!(TimeDelta::try_milliseconds(1001).unwrap().num_seconds(), 1);
759assert_eq!(TimeDelta::try_milliseconds(-999).unwrap().num_seconds(), 0);
760assert_eq!(TimeDelta::try_milliseconds(-1001).unwrap().num_seconds(), -1);
761 }
762763#[test]
764fn test_duration_seconds_max_allowed() {
765let duration = TimeDelta::try_seconds(i64::MAX / 1_000).unwrap();
766assert_eq!(duration.num_seconds(), i64::MAX / 1_000);
767assert_eq!(
768 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
769 i64::MAX as i128 / 1_000 * 1_000_000_000
770);
771 }
772773#[test]
774fn test_duration_seconds_max_overflow() {
775assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none());
776 }
777778#[test]
779 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
780fn test_duration_seconds_max_overflow_panic() {
781let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
782 }
783784#[test]
785fn test_duration_seconds_min_allowed() {
786let duration = TimeDelta::try_seconds(i64::MIN / 1_000).unwrap(); // Same as -i64::MAX / 1_000 due to rounding
787assert_eq!(duration.num_seconds(), i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding
788assert_eq!(
789 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
790 -i64::MAX as i128 / 1_000 * 1_000_000_000
791);
792 }
793794#[test]
795fn test_duration_seconds_min_underflow() {
796assert!(TimeDelta::try_seconds(-i64::MAX / 1_000 - 1).is_none());
797 }
798799#[test]
800 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
801fn test_duration_seconds_min_underflow_panic() {
802let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1);
803 }
804805#[test]
806fn test_duration_as_seconds_f64() {
807assert_eq!(TimeDelta::seconds(1).as_seconds_f64(), 1.0);
808assert_eq!(TimeDelta::seconds(-1).as_seconds_f64(), -1.0);
809assert_eq!(TimeDelta::seconds(100).as_seconds_f64(), 100.0);
810assert_eq!(TimeDelta::seconds(-100).as_seconds_f64(), -100.0);
811812assert_eq!(TimeDelta::milliseconds(500).as_seconds_f64(), 0.5);
813assert_eq!(TimeDelta::milliseconds(-500).as_seconds_f64(), -0.5);
814assert_eq!(TimeDelta::milliseconds(1_500).as_seconds_f64(), 1.5);
815assert_eq!(TimeDelta::milliseconds(-1_500).as_seconds_f64(), -1.5);
816 }
817818#[test]
819fn test_duration_as_seconds_f32() {
820assert_eq!(TimeDelta::seconds(1).as_seconds_f32(), 1.0);
821assert_eq!(TimeDelta::seconds(-1).as_seconds_f32(), -1.0);
822assert_eq!(TimeDelta::seconds(100).as_seconds_f32(), 100.0);
823assert_eq!(TimeDelta::seconds(-100).as_seconds_f32(), -100.0);
824825assert_eq!(TimeDelta::milliseconds(500).as_seconds_f32(), 0.5);
826assert_eq!(TimeDelta::milliseconds(-500).as_seconds_f32(), -0.5);
827assert_eq!(TimeDelta::milliseconds(1_500).as_seconds_f32(), 1.5);
828assert_eq!(TimeDelta::milliseconds(-1_500).as_seconds_f32(), -1.5);
829 }
830831#[test]
832fn test_duration_subsec_nanos() {
833assert_eq!(TimeDelta::zero().subsec_nanos(), 0);
834assert_eq!(TimeDelta::nanoseconds(1).subsec_nanos(), 1);
835assert_eq!(TimeDelta::nanoseconds(-1).subsec_nanos(), -1);
836assert_eq!(TimeDelta::seconds(1).subsec_nanos(), 0);
837assert_eq!(TimeDelta::nanoseconds(1_000_000_001).subsec_nanos(), 1);
838 }
839840#[test]
841fn test_duration_subsec_micros() {
842assert_eq!(TimeDelta::zero().subsec_micros(), 0);
843assert_eq!(TimeDelta::microseconds(1).subsec_micros(), 1);
844assert_eq!(TimeDelta::microseconds(-1).subsec_micros(), -1);
845assert_eq!(TimeDelta::seconds(1).subsec_micros(), 0);
846assert_eq!(TimeDelta::microseconds(1_000_001).subsec_micros(), 1);
847assert_eq!(TimeDelta::nanoseconds(1_000_001_999).subsec_micros(), 1);
848 }
849850#[test]
851fn test_duration_subsec_millis() {
852assert_eq!(TimeDelta::zero().subsec_millis(), 0);
853assert_eq!(TimeDelta::milliseconds(1).subsec_millis(), 1);
854assert_eq!(TimeDelta::milliseconds(-1).subsec_millis(), -1);
855assert_eq!(TimeDelta::seconds(1).subsec_millis(), 0);
856assert_eq!(TimeDelta::milliseconds(1_001).subsec_millis(), 1);
857assert_eq!(TimeDelta::microseconds(1_001_999).subsec_millis(), 1);
858 }
859860#[test]
861fn test_duration_num_milliseconds() {
862assert_eq!(TimeDelta::zero().num_milliseconds(), 0);
863assert_eq!(TimeDelta::try_milliseconds(1).unwrap().num_milliseconds(), 1);
864assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().num_milliseconds(), -1);
865assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0);
866assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1);
867assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0);
868assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1);
869 }
870871#[test]
872fn test_duration_milliseconds_max_allowed() {
873// The maximum number of milliseconds acceptable through the constructor is
874 // equal to the number that can be stored in a TimeDelta.
875let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
876assert_eq!(duration.num_milliseconds(), i64::MAX);
877assert_eq!(
878 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
879 i64::MAX as i128 * 1_000_000
880);
881 }
882883#[test]
884fn test_duration_milliseconds_max_overflow() {
885// Here we ensure that trying to add one millisecond to the maximum storable
886 // value will fail.
887assert!(
888 TimeDelta::try_milliseconds(i64::MAX)
889 .unwrap()
890 .checked_add(&TimeDelta::try_milliseconds(1).unwrap())
891 .is_none()
892 );
893 }
894895#[test]
896fn test_duration_milliseconds_min_allowed() {
897// The minimum number of milliseconds acceptable through the constructor is
898 // not equal to the number that can be stored in a TimeDelta - there is a
899 // difference of one (i64::MIN vs -i64::MAX).
900let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
901assert_eq!(duration.num_milliseconds(), -i64::MAX);
902assert_eq!(
903 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
904 -i64::MAX as i128 * 1_000_000
905);
906 }
907908#[test]
909fn test_duration_milliseconds_min_underflow() {
910// Here we ensure that trying to subtract one millisecond from the minimum
911 // storable value will fail.
912assert!(
913 TimeDelta::try_milliseconds(-i64::MAX)
914 .unwrap()
915 .checked_sub(&TimeDelta::try_milliseconds(1).unwrap())
916 .is_none()
917 );
918 }
919920#[test]
921 #[should_panic(expected = "TimeDelta::milliseconds out of bounds")]
922fn test_duration_milliseconds_min_underflow_panic() {
923// Here we ensure that trying to create a value one millisecond below the
924 // minimum storable value will fail. This test is necessary because the
925 // storable range is -i64::MAX, but the constructor type of i64 will allow
926 // i64::MIN, which is one value below.
927let _ = TimeDelta::milliseconds(i64::MIN); // Same as -i64::MAX - 1
928}
929930#[test]
931fn test_duration_num_microseconds() {
932assert_eq!(TimeDelta::zero().num_microseconds(), Some(0));
933assert_eq!(TimeDelta::microseconds(1).num_microseconds(), Some(1));
934assert_eq!(TimeDelta::microseconds(-1).num_microseconds(), Some(-1));
935assert_eq!(TimeDelta::nanoseconds(999).num_microseconds(), Some(0));
936assert_eq!(TimeDelta::nanoseconds(1001).num_microseconds(), Some(1));
937assert_eq!(TimeDelta::nanoseconds(-999).num_microseconds(), Some(0));
938assert_eq!(TimeDelta::nanoseconds(-1001).num_microseconds(), Some(-1));
939940// overflow checks
941const MICROS_PER_DAY: i64 = 86_400_000_000;
942assert_eq!(
943 TimeDelta::try_days(i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
944Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
945 );
946assert_eq!(
947 TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
948Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
949 );
950assert_eq!(
951 TimeDelta::try_days(i64::MAX / MICROS_PER_DAY + 1).unwrap().num_microseconds(),
952None
953);
954assert_eq!(
955 TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY - 1).unwrap().num_microseconds(),
956None
957);
958 }
959#[test]
960fn test_duration_microseconds_max_allowed() {
961// The number of microseconds acceptable through the constructor is far
962 // fewer than the number that can actually be stored in a TimeDelta, so this
963 // is not a particular insightful test.
964let duration = TimeDelta::microseconds(i64::MAX);
965assert_eq!(duration.num_microseconds(), Some(i64::MAX));
966assert_eq!(
967 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
968 i64::MAX as i128 * 1_000
969);
970// Here we create a TimeDelta with the maximum possible number of
971 // microseconds by creating a TimeDelta with the maximum number of
972 // milliseconds and then checking that the number of microseconds matches
973 // the storage limit.
974let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
975assert!(duration.num_microseconds().is_none());
976assert_eq!(
977 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
978 i64::MAX as i128 * 1_000_000
979);
980 }
981#[test]
982fn test_duration_microseconds_max_overflow() {
983// This test establishes that a TimeDelta can store more microseconds than
984 // are representable through the return of duration.num_microseconds().
985let duration = TimeDelta::microseconds(i64::MAX) + TimeDelta::microseconds(1);
986assert!(duration.num_microseconds().is_none());
987assert_eq!(
988 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
989 (i64::MAX as i128 + 1) * 1_000
990);
991// Here we ensure that trying to add one microsecond to the maximum storable
992 // value will fail.
993assert!(
994 TimeDelta::try_milliseconds(i64::MAX)
995 .unwrap()
996 .checked_add(&TimeDelta::microseconds(1))
997 .is_none()
998 );
999 }
1000#[test]
1001fn test_duration_microseconds_min_allowed() {
1002// The number of microseconds acceptable through the constructor is far
1003 // fewer than the number that can actually be stored in a TimeDelta, so this
1004 // is not a particular insightful test.
1005let duration = TimeDelta::microseconds(i64::MIN);
1006assert_eq!(duration.num_microseconds(), Some(i64::MIN));
1007assert_eq!(
1008 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1009 i64::MIN as i128 * 1_000
1010);
1011// Here we create a TimeDelta with the minimum possible number of
1012 // microseconds by creating a TimeDelta with the minimum number of
1013 // milliseconds and then checking that the number of microseconds matches
1014 // the storage limit.
1015let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
1016assert!(duration.num_microseconds().is_none());
1017assert_eq!(
1018 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1019 -i64::MAX as i128 * 1_000_000
1020);
1021 }
1022#[test]
1023fn test_duration_microseconds_min_underflow() {
1024// This test establishes that a TimeDelta can store more microseconds than
1025 // are representable through the return of duration.num_microseconds().
1026let duration = TimeDelta::microseconds(i64::MIN) - TimeDelta::microseconds(1);
1027assert!(duration.num_microseconds().is_none());
1028assert_eq!(
1029 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1030 (i64::MIN as i128 - 1) * 1_000
1031);
1032// Here we ensure that trying to subtract one microsecond from the minimum
1033 // storable value will fail.
1034assert!(
1035 TimeDelta::try_milliseconds(-i64::MAX)
1036 .unwrap()
1037 .checked_sub(&TimeDelta::microseconds(1))
1038 .is_none()
1039 );
1040 }
10411042#[test]
1043fn test_duration_num_nanoseconds() {
1044assert_eq!(TimeDelta::zero().num_nanoseconds(), Some(0));
1045assert_eq!(TimeDelta::nanoseconds(1).num_nanoseconds(), Some(1));
1046assert_eq!(TimeDelta::nanoseconds(-1).num_nanoseconds(), Some(-1));
10471048// overflow checks
1049const NANOS_PER_DAY: i64 = 86_400_000_000_000;
1050assert_eq!(
1051 TimeDelta::try_days(i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
1052Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
1053 );
1054assert_eq!(
1055 TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
1056Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
1057 );
1058assert_eq!(
1059 TimeDelta::try_days(i64::MAX / NANOS_PER_DAY + 1).unwrap().num_nanoseconds(),
1060None
1061);
1062assert_eq!(
1063 TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY - 1).unwrap().num_nanoseconds(),
1064None
1065);
1066 }
1067#[test]
1068fn test_duration_nanoseconds_max_allowed() {
1069// The number of nanoseconds acceptable through the constructor is far fewer
1070 // than the number that can actually be stored in a TimeDelta, so this is not
1071 // a particular insightful test.
1072let duration = TimeDelta::nanoseconds(i64::MAX);
1073assert_eq!(duration.num_nanoseconds(), Some(i64::MAX));
1074assert_eq!(
1075 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1076 i64::MAX as i128
1077 );
1078// Here we create a TimeDelta with the maximum possible number of nanoseconds
1079 // by creating a TimeDelta with the maximum number of milliseconds and then
1080 // checking that the number of nanoseconds matches the storage limit.
1081let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
1082assert!(duration.num_nanoseconds().is_none());
1083assert_eq!(
1084 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1085 i64::MAX as i128 * 1_000_000
1086);
1087 }
10881089#[test]
1090fn test_duration_nanoseconds_max_overflow() {
1091// This test establishes that a TimeDelta can store more nanoseconds than are
1092 // representable through the return of duration.num_nanoseconds().
1093let duration = TimeDelta::nanoseconds(i64::MAX) + TimeDelta::nanoseconds(1);
1094assert!(duration.num_nanoseconds().is_none());
1095assert_eq!(
1096 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1097 i64::MAX as i128 + 1
1098);
1099// Here we ensure that trying to add one nanosecond to the maximum storable
1100 // value will fail.
1101assert!(
1102 TimeDelta::try_milliseconds(i64::MAX)
1103 .unwrap()
1104 .checked_add(&TimeDelta::nanoseconds(1))
1105 .is_none()
1106 );
1107 }
11081109#[test]
1110fn test_duration_nanoseconds_min_allowed() {
1111// The number of nanoseconds acceptable through the constructor is far fewer
1112 // than the number that can actually be stored in a TimeDelta, so this is not
1113 // a particular insightful test.
1114let duration = TimeDelta::nanoseconds(i64::MIN);
1115assert_eq!(duration.num_nanoseconds(), Some(i64::MIN));
1116assert_eq!(
1117 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1118 i64::MIN as i128
1119 );
1120// Here we create a TimeDelta with the minimum possible number of nanoseconds
1121 // by creating a TimeDelta with the minimum number of milliseconds and then
1122 // checking that the number of nanoseconds matches the storage limit.
1123let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
1124assert!(duration.num_nanoseconds().is_none());
1125assert_eq!(
1126 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1127 -i64::MAX as i128 * 1_000_000
1128);
1129 }
11301131#[test]
1132fn test_duration_nanoseconds_min_underflow() {
1133// This test establishes that a TimeDelta can store more nanoseconds than are
1134 // representable through the return of duration.num_nanoseconds().
1135let duration = TimeDelta::nanoseconds(i64::MIN) - TimeDelta::nanoseconds(1);
1136assert!(duration.num_nanoseconds().is_none());
1137assert_eq!(
1138 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1139 i64::MIN as i128 - 1
1140);
1141// Here we ensure that trying to subtract one nanosecond from the minimum
1142 // storable value will fail.
1143assert!(
1144 TimeDelta::try_milliseconds(-i64::MAX)
1145 .unwrap()
1146 .checked_sub(&TimeDelta::nanoseconds(1))
1147 .is_none()
1148 );
1149 }
11501151#[test]
1152fn test_max() {
1153assert_eq!(
1154 MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128,
1155 i64::MAX as i128 * 1_000_000
1156);
1157assert_eq!(MAX, TimeDelta::try_milliseconds(i64::MAX).unwrap());
1158assert_eq!(MAX.num_milliseconds(), i64::MAX);
1159assert_eq!(MAX.num_microseconds(), None);
1160assert_eq!(MAX.num_nanoseconds(), None);
1161 }
11621163#[test]
1164fn test_min() {
1165assert_eq!(
1166 MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128,
1167 -i64::MAX as i128 * 1_000_000
1168);
1169assert_eq!(MIN, TimeDelta::try_milliseconds(-i64::MAX).unwrap());
1170assert_eq!(MIN.num_milliseconds(), -i64::MAX);
1171assert_eq!(MIN.num_microseconds(), None);
1172assert_eq!(MIN.num_nanoseconds(), None);
1173 }
11741175#[test]
1176fn test_duration_ord() {
1177let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
11781179assert!(milliseconds(1) < milliseconds(2));
1180assert!(milliseconds(2) > milliseconds(1));
1181assert!(milliseconds(-1) > milliseconds(-2));
1182assert!(milliseconds(-2) < milliseconds(-1));
1183assert!(milliseconds(-1) < milliseconds(1));
1184assert!(milliseconds(1) > milliseconds(-1));
1185assert!(milliseconds(0) < milliseconds(1));
1186assert!(milliseconds(0) > milliseconds(-1));
1187assert!(milliseconds(1_001) < milliseconds(1_002));
1188assert!(milliseconds(-1_001) > milliseconds(-1_002));
1189assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891));
1190assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891));
1191assert!(milliseconds(i64::MAX) > milliseconds(i64::MAX - 1));
1192assert!(milliseconds(-i64::MAX) < milliseconds(-i64::MAX + 1));
1193 }
11941195#[test]
1196fn test_duration_checked_ops() {
1197let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1198let seconds = |s| TimeDelta::try_seconds(s).unwrap();
11991200assert_eq!(
1201 milliseconds(i64::MAX).checked_add(&milliseconds(0)),
1202Some(milliseconds(i64::MAX))
1203 );
1204assert_eq!(
1205 milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
1206Some(milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
1207 );
1208assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::microseconds(1000)).is_none());
1209assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::nanoseconds(1)).is_none());
12101211assert_eq!(
1212 milliseconds(-i64::MAX).checked_sub(&milliseconds(0)),
1213Some(milliseconds(-i64::MAX))
1214 );
1215assert_eq!(
1216 milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
1217Some(milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
1218 );
1219assert!(milliseconds(-i64::MAX).checked_sub(&milliseconds(1)).is_none());
1220assert!(milliseconds(-i64::MAX).checked_sub(&TimeDelta::nanoseconds(1)).is_none());
12211222assert!(seconds(i64::MAX / 1000).checked_mul(2000).is_none());
1223assert!(seconds(i64::MIN / 1000).checked_mul(2000).is_none());
1224assert!(seconds(1).checked_div(0).is_none());
1225 }
12261227#[test]
1228fn test_duration_abs() {
1229let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
12301231assert_eq!(milliseconds(1300).abs(), milliseconds(1300));
1232assert_eq!(milliseconds(1000).abs(), milliseconds(1000));
1233assert_eq!(milliseconds(300).abs(), milliseconds(300));
1234assert_eq!(milliseconds(0).abs(), milliseconds(0));
1235assert_eq!(milliseconds(-300).abs(), milliseconds(300));
1236assert_eq!(milliseconds(-700).abs(), milliseconds(700));
1237assert_eq!(milliseconds(-1000).abs(), milliseconds(1000));
1238assert_eq!(milliseconds(-1300).abs(), milliseconds(1300));
1239assert_eq!(milliseconds(-1700).abs(), milliseconds(1700));
1240assert_eq!(milliseconds(-i64::MAX).abs(), milliseconds(i64::MAX));
1241 }
12421243#[test]
1244 #[allow(clippy::erasing_op)]
1245fn test_duration_mul() {
1246assert_eq!(TimeDelta::zero() * i32::MAX, TimeDelta::zero());
1247assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero());
1248assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero());
1249assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1));
1250assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::try_seconds(1).unwrap());
1251assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1252assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1253assert_eq!(
1254 TimeDelta::nanoseconds(30) * 333_333_333,
1255 TimeDelta::try_seconds(10).unwrap() - TimeDelta::nanoseconds(10)
1256 );
1257assert_eq!(
1258 (TimeDelta::nanoseconds(1)
1259 + TimeDelta::try_seconds(1).unwrap()
1260 + TimeDelta::try_days(1).unwrap())
1261 * 3,
1262 TimeDelta::nanoseconds(3)
1263 + TimeDelta::try_seconds(3).unwrap()
1264 + TimeDelta::try_days(3).unwrap()
1265 );
1266assert_eq!(
1267 TimeDelta::try_milliseconds(1500).unwrap() * -2,
1268 TimeDelta::try_seconds(-3).unwrap()
1269 );
1270assert_eq!(
1271 TimeDelta::try_milliseconds(-1500).unwrap() * 2,
1272 TimeDelta::try_seconds(-3).unwrap()
1273 );
1274 }
12751276#[test]
1277fn test_duration_div() {
1278assert_eq!(TimeDelta::zero() / i32::MAX, TimeDelta::zero());
1279assert_eq!(TimeDelta::zero() / i32::MIN, TimeDelta::zero());
1280assert_eq!(TimeDelta::nanoseconds(123_456_789) / 1, TimeDelta::nanoseconds(123_456_789));
1281assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789));
1282assert_eq!(-TimeDelta::nanoseconds(123_456_789) / -1, TimeDelta::nanoseconds(123_456_789));
1283assert_eq!(-TimeDelta::nanoseconds(123_456_789) / 1, -TimeDelta::nanoseconds(123_456_789));
1284assert_eq!(TimeDelta::try_seconds(1).unwrap() / 3, TimeDelta::nanoseconds(333_333_333));
1285assert_eq!(TimeDelta::try_seconds(4).unwrap() / 3, TimeDelta::nanoseconds(1_333_333_333));
1286assert_eq!(
1287 TimeDelta::try_seconds(-1).unwrap() / 2,
1288 TimeDelta::try_milliseconds(-500).unwrap()
1289 );
1290assert_eq!(
1291 TimeDelta::try_seconds(1).unwrap() / -2,
1292 TimeDelta::try_milliseconds(-500).unwrap()
1293 );
1294assert_eq!(
1295 TimeDelta::try_seconds(-1).unwrap() / -2,
1296 TimeDelta::try_milliseconds(500).unwrap()
1297 );
1298assert_eq!(TimeDelta::try_seconds(-4).unwrap() / 3, TimeDelta::nanoseconds(-1_333_333_333));
1299assert_eq!(TimeDelta::try_seconds(-4).unwrap() / -3, TimeDelta::nanoseconds(1_333_333_333));
1300 }
13011302#[test]
1303fn test_duration_sum() {
1304let duration_list_1 = [TimeDelta::zero(), TimeDelta::try_seconds(1).unwrap()];
1305let sum_1: TimeDelta = duration_list_1.iter().sum();
1306assert_eq!(sum_1, TimeDelta::try_seconds(1).unwrap());
13071308let duration_list_2 = [
1309 TimeDelta::zero(),
1310 TimeDelta::try_seconds(1).unwrap(),
1311 TimeDelta::try_seconds(6).unwrap(),
1312 TimeDelta::try_seconds(10).unwrap(),
1313 ];
1314let sum_2: TimeDelta = duration_list_2.iter().sum();
1315assert_eq!(sum_2, TimeDelta::try_seconds(17).unwrap());
13161317let duration_arr = [
1318 TimeDelta::zero(),
1319 TimeDelta::try_seconds(1).unwrap(),
1320 TimeDelta::try_seconds(6).unwrap(),
1321 TimeDelta::try_seconds(10).unwrap(),
1322 ];
1323let sum_3: TimeDelta = duration_arr.into_iter().sum();
1324assert_eq!(sum_3, TimeDelta::try_seconds(17).unwrap());
1325 }
13261327#[test]
1328fn test_duration_fmt() {
1329assert_eq!(TimeDelta::zero().to_string(), "P0D");
1330assert_eq!(TimeDelta::try_days(42).unwrap().to_string(), "PT3628800S");
1331assert_eq!(TimeDelta::try_days(-42).unwrap().to_string(), "-PT3628800S");
1332assert_eq!(TimeDelta::try_seconds(42).unwrap().to_string(), "PT42S");
1333assert_eq!(TimeDelta::try_milliseconds(42).unwrap().to_string(), "PT0.042S");
1334assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S");
1335assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S");
1336assert_eq!(
1337 (TimeDelta::try_days(7).unwrap() + TimeDelta::try_milliseconds(6543).unwrap())
1338 .to_string(),
1339"PT604806.543S"
1340);
1341assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().to_string(), "-PT86401S");
1342assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S");
13431344// the format specifier should have no effect on `TimeDelta`
1345assert_eq!(
1346format!(
1347"{:30}",
1348 TimeDelta::try_days(1).unwrap() + TimeDelta::try_milliseconds(2345).unwrap()
1349 ),
1350"PT86402.345S"
1351);
1352 }
13531354#[test]
1355fn test_to_std() {
1356assert_eq!(TimeDelta::try_seconds(1).unwrap().to_std(), Ok(Duration::new(1, 0)));
1357assert_eq!(TimeDelta::try_seconds(86_401).unwrap().to_std(), Ok(Duration::new(86_401, 0)));
1358assert_eq!(
1359 TimeDelta::try_milliseconds(123).unwrap().to_std(),
1360Ok(Duration::new(0, 123_000_000))
1361 );
1362assert_eq!(
1363 TimeDelta::try_milliseconds(123_765).unwrap().to_std(),
1364Ok(Duration::new(123, 765_000_000))
1365 );
1366assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777)));
1367assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000)));
1368assert_eq!(TimeDelta::try_seconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1369assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1370 }
13711372#[test]
1373fn test_from_std() {
1374assert_eq!(
1375Ok(TimeDelta::try_seconds(1).unwrap()),
1376 TimeDelta::from_std(Duration::new(1, 0))
1377 );
1378assert_eq!(
1379Ok(TimeDelta::try_seconds(86_401).unwrap()),
1380 TimeDelta::from_std(Duration::new(86_401, 0))
1381 );
1382assert_eq!(
1383Ok(TimeDelta::try_milliseconds(123).unwrap()),
1384 TimeDelta::from_std(Duration::new(0, 123_000_000))
1385 );
1386assert_eq!(
1387Ok(TimeDelta::try_milliseconds(123_765).unwrap()),
1388 TimeDelta::from_std(Duration::new(123, 765_000_000))
1389 );
1390assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777)));
1391assert_eq!(Ok(MAX), TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_000)));
1392assert_eq!(
1393 TimeDelta::from_std(Duration::new(9_223_372_036_854_776, 0)),
1394Err(OutOfRangeError(()))
1395 );
1396assert_eq!(
1397 TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_001)),
1398Err(OutOfRangeError(()))
1399 );
1400 }
14011402#[test]
1403fn test_duration_const() {
1404const ONE_WEEK: TimeDelta = expect(TimeDelta::try_weeks(1), "");
1405const ONE_DAY: TimeDelta = expect(TimeDelta::try_days(1), "");
1406const ONE_HOUR: TimeDelta = expect(TimeDelta::try_hours(1), "");
1407const ONE_MINUTE: TimeDelta = expect(TimeDelta::try_minutes(1), "");
1408const ONE_SECOND: TimeDelta = expect(TimeDelta::try_seconds(1), "");
1409const ONE_MILLI: TimeDelta = expect(TimeDelta::try_milliseconds(1), "");
1410const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1);
1411const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1);
1412let combo: TimeDelta = ONE_WEEK
1413 + ONE_DAY
1414 + ONE_HOUR
1415 + ONE_MINUTE
1416 + ONE_SECOND
1417 + ONE_MILLI
1418 + ONE_MICRO
1419 + ONE_NANO;
14201421assert!(ONE_WEEK != TimeDelta::zero());
1422assert!(ONE_DAY != TimeDelta::zero());
1423assert!(ONE_HOUR != TimeDelta::zero());
1424assert!(ONE_MINUTE != TimeDelta::zero());
1425assert!(ONE_SECOND != TimeDelta::zero());
1426assert!(ONE_MILLI != TimeDelta::zero());
1427assert!(ONE_MICRO != TimeDelta::zero());
1428assert!(ONE_NANO != TimeDelta::zero());
1429assert_eq!(
1430 combo,
1431 TimeDelta::try_seconds(86400 * 7 + 86400 + 3600 + 60 + 1).unwrap()
1432 + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000)
1433 );
1434 }
14351436#[test]
1437 #[cfg(feature = "rkyv-validation")]
1438fn test_rkyv_validation() {
1439let duration = TimeDelta::try_seconds(1).unwrap();
1440let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
1441assert_eq!(rkyv::from_bytes::<TimeDelta>(&bytes).unwrap(), duration);
1442 }
1443}