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))]
62pub struct TimeDelta {
63 secs: i64,
64 nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
65}
6667/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
68pub(crate) const MIN: TimeDelta = TimeDelta {
69 secs: -i64::MAX / MILLIS_PER_SEC - 1,
70 nanos: NANOS_PER_SEC + (-i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
71};
7273/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
74pub(crate) const MAX: TimeDelta = TimeDelta {
75 secs: i64::MAX / MILLIS_PER_SEC,
76 nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
77};
7879impl TimeDelta {
80/// Makes a new `TimeDelta` with given number of seconds and nanoseconds.
81 ///
82 /// # Errors
83 ///
84 /// Returns `None` when the duration is out of bounds, or if `nanos` ≥ 1,000,000,000.
85pub const fn new(secs: i64, nanos: u32) -> Option<TimeDelta> {
86if secs < MIN.secs
87 || secs > MAX.secs
88 || nanos >= 1_000_000_000
89|| (secs == MAX.secs && nanos > MAX.nanos as u32)
90 || (secs == MIN.secs && nanos < MIN.nanos as u32)
91 {
92return None;
93 }
94Some(TimeDelta { secs, nanos: nanosas i32 })
95 }
9697/// Makes a new `TimeDelta` with the given number of weeks.
98 ///
99 /// Equivalent to `TimeDelta::seconds(weeks * 7 * 24 * 60 * 60)` with
100 /// overflow checks.
101 ///
102 /// # Panics
103 ///
104 /// Panics when the duration is out of bounds.
105#[inline]
106 #[must_use]
107pub const fn weeks(weeks: i64) -> TimeDelta {
108expect(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds")
109 }
110111/// Makes a new `TimeDelta` with the given number of weeks.
112 ///
113 /// Equivalent to `TimeDelta::try_seconds(weeks * 7 * 24 * 60 * 60)` with
114 /// overflow checks.
115 ///
116 /// # Errors
117 ///
118 /// Returns `None` when the `TimeDelta` would be out of bounds.
119#[inline]
120pub const fn try_weeks(weeks: i64) -> Option<TimeDelta> {
121TimeDelta::try_seconds(match weeks.checked_mul(SECS_PER_WEEK) { Some(v) => v, None => return None, }try_opt!(weeks.checked_mul(SECS_PER_WEEK)))
122 }
123124/// Makes a new `TimeDelta` with the given number of days.
125 ///
126 /// Equivalent to `TimeDelta::seconds(days * 24 * 60 * 60)` with overflow
127 /// checks.
128 ///
129 /// # Panics
130 ///
131 /// Panics when the `TimeDelta` would be out of bounds.
132#[inline]
133 #[must_use]
134pub const fn days(days: i64) -> TimeDelta {
135expect(TimeDelta::try_days(days), "TimeDelta::days out of bounds")
136 }
137138/// Makes a new `TimeDelta` with the given number of days.
139 ///
140 /// Equivalent to `TimeDelta::try_seconds(days * 24 * 60 * 60)` with overflow
141 /// checks.
142 ///
143 /// # Errors
144 ///
145 /// Returns `None` when the `TimeDelta` would be out of bounds.
146#[inline]
147pub const fn try_days(days: i64) -> Option<TimeDelta> {
148TimeDelta::try_seconds(match days.checked_mul(SECS_PER_DAY) { Some(v) => v, None => return None, }try_opt!(days.checked_mul(SECS_PER_DAY)))
149 }
150151/// Makes a new `TimeDelta` with the given number of hours.
152 ///
153 /// Equivalent to `TimeDelta::seconds(hours * 60 * 60)` with overflow checks.
154 ///
155 /// # Panics
156 ///
157 /// Panics when the `TimeDelta` would be out of bounds.
158#[inline]
159 #[must_use]
160pub const fn hours(hours: i64) -> TimeDelta {
161expect(TimeDelta::try_hours(hours), "TimeDelta::hours out of bounds")
162 }
163164/// Makes a new `TimeDelta` with the given number of hours.
165 ///
166 /// Equivalent to `TimeDelta::try_seconds(hours * 60 * 60)` with overflow checks.
167 ///
168 /// # Errors
169 ///
170 /// Returns `None` when the `TimeDelta` would be out of bounds.
171#[inline]
172pub const fn try_hours(hours: i64) -> Option<TimeDelta> {
173TimeDelta::try_seconds(match hours.checked_mul(SECS_PER_HOUR) { Some(v) => v, None => return None, }try_opt!(hours.checked_mul(SECS_PER_HOUR)))
174 }
175176/// Makes a new `TimeDelta` with the given number of minutes.
177 ///
178 /// Equivalent to `TimeDelta::seconds(minutes * 60)` with overflow checks.
179 ///
180 /// # Panics
181 ///
182 /// Panics when the `TimeDelta` would be out of bounds.
183#[inline]
184 #[must_use]
185pub const fn minutes(minutes: i64) -> TimeDelta {
186expect(TimeDelta::try_minutes(minutes), "TimeDelta::minutes out of bounds")
187 }
188189/// Makes a new `TimeDelta` with the given number of minutes.
190 ///
191 /// Equivalent to `TimeDelta::try_seconds(minutes * 60)` with overflow checks.
192 ///
193 /// # Errors
194 ///
195 /// Returns `None` when the `TimeDelta` would be out of bounds.
196#[inline]
197pub const fn try_minutes(minutes: i64) -> Option<TimeDelta> {
198TimeDelta::try_seconds(match minutes.checked_mul(SECS_PER_MINUTE) {
Some(v) => v,
None => return None,
}try_opt!(minutes.checked_mul(SECS_PER_MINUTE)))
199 }
200201/// Makes a new `TimeDelta` with the given number of seconds.
202 ///
203 /// # Panics
204 ///
205 /// Panics when `seconds` is more than `i64::MAX / 1_000` or less than `-i64::MAX / 1_000`
206 /// (in this context, this is the same as `i64::MIN / 1_000` due to rounding).
207#[inline]
208 #[must_use]
209pub const fn seconds(seconds: i64) -> TimeDelta {
210expect(TimeDelta::try_seconds(seconds), "TimeDelta::seconds out of bounds")
211 }
212213/// Makes a new `TimeDelta` with the given number of seconds.
214 ///
215 /// # Errors
216 ///
217 /// Returns `None` when `seconds` is more than `i64::MAX / 1_000` or less than
218 /// `-i64::MAX / 1_000` (in this context, this is the same as `i64::MIN / 1_000` due to
219 /// rounding).
220#[inline]
221pub const fn try_seconds(seconds: i64) -> Option<TimeDelta> {
222TimeDelta::new(seconds, 0)
223 }
224225/// Makes a new `TimeDelta` with the given number of milliseconds.
226 ///
227 /// # Panics
228 ///
229 /// Panics when the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more than
230 /// `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
231#[inline]
232pub const fn milliseconds(milliseconds: i64) -> TimeDelta {
233expect(TimeDelta::try_milliseconds(milliseconds), "TimeDelta::milliseconds out of bounds")
234 }
235236/// Makes a new `TimeDelta` with the given number of milliseconds.
237 ///
238 /// # Errors
239 ///
240 /// Returns `None` the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more
241 /// than `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
242#[inline]
243pub const fn try_milliseconds(milliseconds: i64) -> Option<TimeDelta> {
244// We don't need to compare against MAX, as this function accepts an
245 // i64, and MAX is aligned to i64::MAX milliseconds.
246if milliseconds < -i64::MAX {
247return None;
248 }
249let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
250let d = TimeDelta { secs, nanos: millisas i32 * NANOS_PER_MILLI };
251Some(d)
252 }
253254/// Makes a new `TimeDelta` with the given number of microseconds.
255 ///
256 /// The number of microseconds acceptable by this constructor is less than
257 /// the total number that can actually be stored in a `TimeDelta`, so it is
258 /// not possible to specify a value that would be out of bounds. This
259 /// function is therefore infallible.
260#[inline]
261pub const fn microseconds(microseconds: i64) -> TimeDelta {
262let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
263let nanos = microsas i32 * NANOS_PER_MICRO;
264TimeDelta { secs, nanos }
265 }
266267/// Makes a new `TimeDelta` with the given number of nanoseconds.
268 ///
269 /// The number of nanoseconds acceptable by this constructor is less than
270 /// the total number that can actually be stored in a `TimeDelta`, so it is
271 /// not possible to specify a value that would be out of bounds. This
272 /// function is therefore infallible.
273#[inline]
274pub const fn nanoseconds(nanos: i64) -> TimeDelta {
275let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SECas i64);
276TimeDelta { secs, nanos: nanosas i32 }
277 }
278279/// Returns the total number of whole weeks in the `TimeDelta`.
280#[inline]
281pub const fn num_weeks(&self) -> i64 {
282self.num_days() / 7
283}
284285/// Returns the total number of whole days in the `TimeDelta`.
286#[inline]
287pub const fn num_days(&self) -> i64 {
288self.num_seconds() / SECS_PER_DAY289 }
290291/// Returns the total number of whole hours in the `TimeDelta`.
292#[inline]
293pub const fn num_hours(&self) -> i64 {
294self.num_seconds() / SECS_PER_HOUR295 }
296297/// Returns the total number of whole minutes in the `TimeDelta`.
298#[inline]
299pub const fn num_minutes(&self) -> i64 {
300self.num_seconds() / SECS_PER_MINUTE301 }
302303/// Returns the total number of whole seconds in the `TimeDelta`.
304pub const fn num_seconds(&self) -> i64 {
305// If secs is negative, nanos should be subtracted from the duration.
306if self.secs < 0 && self.nanos > 0 { self.secs + 1 } else { self.secs }
307 }
308309/// Returns the fractional number of seconds in the `TimeDelta`.
310pub fn as_seconds_f64(self) -> f64 {
311self.secs as f64 + self.nanos as f64 / NANOS_PER_SECas f64312 }
313314/// Returns the fractional number of seconds in the `TimeDelta`.
315pub fn as_seconds_f32(self) -> f32 {
316self.secs as f32 + self.nanos as f32 / NANOS_PER_SECas f32317 }
318319/// Returns the total number of whole milliseconds in the `TimeDelta`.
320pub const fn num_milliseconds(&self) -> i64 {
321// A proper TimeDelta will not overflow, because MIN and MAX are defined such
322 // that the range is within the bounds of an i64, from -i64::MAX through to
323 // +i64::MAX inclusive. Notably, i64::MIN is excluded from this range.
324let secs_part = self.num_seconds() * MILLIS_PER_SEC;
325let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI;
326secs_part + nanos_partas i64327 }
328329/// Returns the number of milliseconds in the fractional part of the duration.
330 ///
331 /// This is the number of milliseconds such that
332 /// `subsec_millis() + num_seconds() * 1_000` is the truncated number of
333 /// milliseconds in the duration.
334pub const fn subsec_millis(&self) -> i32 {
335self.subsec_nanos() / NANOS_PER_MILLI336 }
337338/// Returns the total number of whole microseconds in the `TimeDelta`,
339 /// or `None` on overflow (exceeding 2^63 microseconds in either direction).
340pub const fn num_microseconds(&self) -> Option<i64> {
341let 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));
342let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO;
343secs_part.checked_add(nanos_partas i64)
344 }
345346/// Returns the number of microseconds in the fractional part of the duration.
347 ///
348 /// This is the number of microseconds such that
349 /// `subsec_micros() + num_seconds() * 1_000_000` is the truncated number of
350 /// microseconds in the duration.
351pub const fn subsec_micros(&self) -> i32 {
352self.subsec_nanos() / NANOS_PER_MICRO353 }
354355/// Returns the total number of whole nanoseconds in the `TimeDelta`,
356 /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
357pub const fn num_nanoseconds(&self) -> Option<i64> {
358let 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));
359let nanos_part = self.subsec_nanos();
360secs_part.checked_add(nanos_partas i64)
361 }
362363/// Returns the number of nanoseconds in the fractional part of the duration.
364 ///
365 /// This is the number of nanoseconds such that
366 /// `subsec_nanos() + num_seconds() * 1_000_000_000` is the total number of
367 /// nanoseconds in the `TimeDelta`.
368pub const fn subsec_nanos(&self) -> i32 {
369if self.secs < 0 && self.nanos > 0 { self.nanos - NANOS_PER_SEC } else { self.nanos }
370 }
371372/// Add two `TimeDelta`s, returning `None` if overflow occurred.
373#[must_use]
374pub const fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
375// No overflow checks here because we stay comfortably within the range of an `i64`.
376 // Range checks happen in `TimeDelta::new`.
377let mut secs = self.secs + rhs.secs;
378let mut nanos = self.nanos + rhs.nanos;
379if nanos >= NANOS_PER_SEC {
380nanos -= NANOS_PER_SEC;
381secs += 1;
382 }
383TimeDelta::new(secs, nanosas u32)
384 }
385386/// Subtract two `TimeDelta`s, returning `None` if overflow occurred.
387#[must_use]
388pub const fn checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
389// No overflow checks here because we stay comfortably within the range of an `i64`.
390 // Range checks happen in `TimeDelta::new`.
391let mut secs = self.secs - rhs.secs;
392let mut nanos = self.nanos - rhs.nanos;
393if nanos < 0 {
394nanos += NANOS_PER_SEC;
395secs -= 1;
396 }
397TimeDelta::new(secs, nanosas u32)
398 }
399400/// Multiply a `TimeDelta` with a i32, returning `None` if overflow occurred.
401#[must_use]
402pub const fn checked_mul(&self, rhs: i32) -> Option<TimeDelta> {
403// Multiply nanoseconds as i64, because it cannot overflow that way.
404let total_nanos = self.nanos as i64 * rhsas i64;
405let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SECas i64);
406// Multiply seconds as i128 to prevent overflow
407let secs: i128 = self.secs as i128 * rhsas i128 + extra_secsas i128;
408if secs <= i64::MINas i128 || secs >= i64::MAXas i128 {
409return None;
410 };
411Some(TimeDelta { secs: secsas i64, nanos: nanosas i32 })
412 }
413414/// Divide a `TimeDelta` with a i32, returning `None` if dividing by 0.
415#[must_use]
416pub const fn checked_div(&self, rhs: i32) -> Option<TimeDelta> {
417if rhs == 0 {
418return None;
419 }
420let secs = self.secs / rhsas i64;
421let carry = self.secs % rhsas i64;
422let extra_nanos = carry * NANOS_PER_SECas i64 / rhsas i64;
423let nanos = self.nanos / rhs + extra_nanosas i32;
424425let (secs, nanos) = match nanos {
426i32::MIN..=-1 => (secs - 1, nanos + NANOS_PER_SEC),
427NANOS_PER_SEC..=i32::MAX => (secs + 1, nanos - NANOS_PER_SEC),
428_ => (secs, nanos),
429 };
430431Some(TimeDelta { secs, nanos })
432 }
433434/// Returns the `TimeDelta` as an absolute (non-negative) value.
435#[inline]
436pub const fn abs(&self) -> TimeDelta {
437if self.secs < 0 && self.nanos != 0 {
438TimeDelta { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos }
439 } else {
440TimeDelta { secs: self.secs.abs(), nanos: self.nanos }
441 }
442 }
443444/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
445#[deprecated(since = "0.4.39", note = "Use `TimeDelta::MIN` instead")]
446 #[inline]
447pub const fn min_value() -> TimeDelta {
448MIN449 }
450451/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
452#[deprecated(since = "0.4.39", note = "Use `TimeDelta::MAX` instead")]
453 #[inline]
454pub const fn max_value() -> TimeDelta {
455MAX456 }
457458/// A `TimeDelta` where the stored seconds and nanoseconds are equal to zero.
459#[inline]
460pub const fn zero() -> TimeDelta {
461TimeDelta { secs: 0, nanos: 0 }
462 }
463464/// Returns `true` if the `TimeDelta` equals `TimeDelta::zero()`.
465#[inline]
466pub const fn is_zero(&self) -> bool {
467self.secs == 0 && self.nanos == 0
468}
469470/// Creates a `TimeDelta` object from `std::time::Duration`
471 ///
472 /// This function errors when original duration is larger than the maximum
473 /// value supported for this type.
474pub const fn from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError> {
475// We need to check secs as u64 before coercing to i64
476if duration.as_secs() > MAX.secs as u64 {
477return Err(OutOfRangeError(()));
478 }
479match TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos()) {
480Some(d) => Ok(d),
481None => Err(OutOfRangeError(())),
482 }
483 }
484485/// Creates a `std::time::Duration` object from a `TimeDelta`.
486 ///
487 /// This function errors when duration is less than zero. As standard
488 /// library implementation is limited to non-negative values.
489pub const fn to_std(&self) -> Result<Duration, OutOfRangeError> {
490if self.secs < 0 {
491return Err(OutOfRangeError(()));
492 }
493Ok(Duration::new(self.secs as u64, self.nanos as u32))
494 }
495496/// This duplicates `Neg::neg` because trait methods can't be const yet.
497pub(crate) const fn neg(self) -> TimeDelta {
498let (secs_diff, nanos) = match self.nanos {
4990 => (0, 0),
500 nanos => (1, NANOS_PER_SEC - nanos),
501 };
502TimeDelta { secs: -self.secs - secs_diff, nanos }
503 }
504505/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
506pub const MIN: Self = MIN;
507508/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
509pub const MAX: Self = MAX;
510}
511512impl Negfor TimeDelta {
513type Output = TimeDelta;
514515#[inline]
516fn neg(self) -> TimeDelta {
517let (secs_diff, nanos) = match self.nanos {
5180 => (0, 0),
519 nanos => (1, NANOS_PER_SEC - nanos),
520 };
521TimeDelta { secs: -self.secs - secs_diff, nanos }
522 }
523}
524525impl Addfor TimeDelta {
526type Output = TimeDelta;
527528fn add(self, rhs: TimeDelta) -> TimeDelta {
529self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed")
530 }
531}
532533impl Subfor TimeDelta {
534type Output = TimeDelta;
535536fn sub(self, rhs: TimeDelta) -> TimeDelta {
537self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed")
538 }
539}
540541impl AddAssignfor TimeDelta {
542fn add_assign(&mut self, rhs: TimeDelta) {
543let new = self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed");
544*self = new;
545 }
546}
547548impl SubAssignfor TimeDelta {
549fn sub_assign(&mut self, rhs: TimeDelta) {
550let new = self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed");
551*self = new;
552 }
553}
554555impl Mul<i32> for TimeDelta {
556type Output = TimeDelta;
557558fn mul(self, rhs: i32) -> TimeDelta {
559self.checked_mul(rhs).expect("`TimeDelta * i32` overflowed")
560 }
561}
562563impl Div<i32> for TimeDelta {
564type Output = TimeDelta;
565566fn div(self, rhs: i32) -> TimeDelta {
567self.checked_div(rhs).expect("`i32` is zero")
568 }
569}
570571impl<'a> core::iter::Sum<&'a TimeDelta> for TimeDelta {
572fn sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta {
573iter.fold(TimeDelta::zero(), |acc, x| acc + *x)
574 }
575}
576577impl core::iter::Sum<TimeDelta> for TimeDelta {
578fn sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta {
579iter.fold(TimeDelta::zero(), |acc, x| acc + x)
580 }
581}
582583impl fmt::Displayfor TimeDelta {
584/// Format a `TimeDelta` using the [ISO 8601] format
585 ///
586 /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601#Durations
587fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
588// technically speaking, negative duration is not valid ISO 8601,
589 // but we need to print it anyway.
590let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
591592f.write_fmt(format_args!("{0}P", sign))write!(f, "{sign}P")?;
593// Plenty of ways to encode an empty string. `P0D` is short and not too strange.
594if abs.secs == 0 && abs.nanos == 0 {
595return f.write_str("0D");
596 }
597598f.write_fmt(format_args!("T{0}", abs.secs)format_args!("T{}", abs.secs))?;
599600if abs.nanos > 0 {
601// Count the number of significant digits, while removing all trailing zero's.
602let mut figures = 9usize;
603let mut fraction_digits = abs.nanos;
604loop {
605let div = fraction_digits / 10;
606let last_digit = fraction_digits % 10;
607if last_digit != 0 {
608break;
609 }
610fraction_digits = div;
611figures -= 1;
612 }
613f.write_fmt(format_args!(".{0:01$}", fraction_digits, figures)format_args!(".{fraction_digits:0figures$}"))?;
614 }
615f.write_str("S")?;
616Ok(())
617 }
618}
619620/// Represents error when converting `TimeDelta` to/from a standard library
621/// implementation
622///
623/// The `std::time::Duration` supports a range from zero to `u64::MAX`
624/// *seconds*, while this module supports signed range of up to
625/// `i64::MAX` of *milliseconds*.
626#[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)]
627pub struct OutOfRangeError(());
628629impl fmt::Displayfor OutOfRangeError {
630fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
631f.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")632 }
633}
634635#[cfg(any(feature = "std", feature = "core-error"))]
636impl Errorfor OutOfRangeError {
637#[allow(deprecated)]
638fn description(&self) -> &str {
639"out of range error"
640}
641}
642643#[inline]
644const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
645 (this.div_euclid(other), this.rem_euclid(other))
646}
647648#[cfg(all(feature = "arbitrary", feature = "std"))]
649impl arbitrary::Arbitrary<'_> for TimeDelta {
650fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta> {
651const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1;
652const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
653654let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
655let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?;
656let duration = TimeDelta { secs, nanos };
657658if duration < MIN || duration > MAX {
659Err(arbitrary::Error::IncorrectFormat)
660 } else {
661Ok(duration)
662 }
663 }
664}
665666#[cfg(feature = "serde")]
667mod serde {
668use super::TimeDelta;
669use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
670671impl Serialize for TimeDelta {
672fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
673 <(i64, i32) as Serialize>::serialize(&(self.secs, self.nanos), serializer)
674 }
675 }
676677impl<'de> Deserialize<'de> for TimeDelta {
678fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
679let (secs, nanos) = <(i64, i32) as Deserialize>::deserialize(deserializer)?;
680 TimeDelta::new(secs, nanos as u32).ok_or(Error::custom("TimeDelta out of bounds"))
681 }
682 }
683684#[cfg(test)]
685mod tests {
686use super::{super::MAX, TimeDelta};
687688#[test]
689fn test_serde() {
690let duration = TimeDelta::new(123, 456).unwrap();
691assert_eq!(
692 serde_json::from_value::<TimeDelta>(serde_json::to_value(duration).unwrap())
693 .unwrap(),
694 duration
695 );
696 }
697698#[test]
699 #[should_panic(expected = "TimeDelta out of bounds")]
700fn test_serde_oob_panic() {
701let _ =
702 serde_json::from_value::<TimeDelta>(serde_json::json!([MAX.secs + 1, 0])).unwrap();
703 }
704 }
705}
706707#[cfg(test)]
708mod tests {
709use super::OutOfRangeError;
710use super::{MAX, MIN, TimeDelta};
711use crate::expect;
712use core::time::Duration;
713714#[test]
715fn test_duration() {
716let days = |d| TimeDelta::try_days(d).unwrap();
717let seconds = |s| TimeDelta::try_seconds(s).unwrap();
718719assert!(seconds(1) != TimeDelta::zero());
720assert_eq!(seconds(1) + seconds(2), seconds(3));
721assert_eq!(seconds(86_399) + seconds(4), days(1) + seconds(3));
722assert_eq!(days(10) - seconds(1000), seconds(863_000));
723assert_eq!(days(10) - seconds(1_000_000), seconds(-136_000));
724assert_eq!(
725 days(2) + seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
726 days(3) + TimeDelta::nanoseconds(234_567_890)
727 );
728assert_eq!(-days(3), days(-3));
729assert_eq!(-(days(3) + seconds(70)), days(-4) + seconds(86_400 - 70));
730731let mut d = TimeDelta::default();
732 d += TimeDelta::try_minutes(1).unwrap();
733 d -= seconds(30);
734assert_eq!(d, seconds(30));
735 }
736737#[test]
738fn test_duration_num_days() {
739assert_eq!(TimeDelta::zero().num_days(), 0);
740assert_eq!(TimeDelta::try_days(1).unwrap().num_days(), 1);
741assert_eq!(TimeDelta::try_days(-1).unwrap().num_days(), -1);
742assert_eq!(TimeDelta::try_seconds(86_399).unwrap().num_days(), 0);
743assert_eq!(TimeDelta::try_seconds(86_401).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_days(i32::MAX as i64).unwrap().num_days(), i32::MAX as i64);
747assert_eq!(TimeDelta::try_days(i32::MIN as i64).unwrap().num_days(), i32::MIN as i64);
748 }
749750#[test]
751fn test_duration_num_seconds() {
752assert_eq!(TimeDelta::zero().num_seconds(), 0);
753assert_eq!(TimeDelta::try_seconds(1).unwrap().num_seconds(), 1);
754assert_eq!(TimeDelta::try_seconds(-1).unwrap().num_seconds(), -1);
755assert_eq!(TimeDelta::try_milliseconds(999).unwrap().num_seconds(), 0);
756assert_eq!(TimeDelta::try_milliseconds(1001).unwrap().num_seconds(), 1);
757assert_eq!(TimeDelta::try_milliseconds(-999).unwrap().num_seconds(), 0);
758assert_eq!(TimeDelta::try_milliseconds(-1001).unwrap().num_seconds(), -1);
759 }
760761#[test]
762fn test_duration_seconds_max_allowed() {
763let duration = TimeDelta::try_seconds(i64::MAX / 1_000).unwrap();
764assert_eq!(duration.num_seconds(), i64::MAX / 1_000);
765assert_eq!(
766 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
767 i64::MAX as i128 / 1_000 * 1_000_000_000
768);
769 }
770771#[test]
772fn test_duration_seconds_max_overflow() {
773assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none());
774 }
775776#[test]
777 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
778fn test_duration_seconds_max_overflow_panic() {
779let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
780 }
781782#[test]
783fn test_duration_seconds_min_allowed() {
784let duration = TimeDelta::try_seconds(i64::MIN / 1_000).unwrap(); // Same as -i64::MAX / 1_000 due to rounding
785assert_eq!(duration.num_seconds(), i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding
786assert_eq!(
787 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
788 -i64::MAX as i128 / 1_000 * 1_000_000_000
789);
790 }
791792#[test]
793fn test_duration_seconds_min_underflow() {
794assert!(TimeDelta::try_seconds(-i64::MAX / 1_000 - 1).is_none());
795 }
796797#[test]
798 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
799fn test_duration_seconds_min_underflow_panic() {
800let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1);
801 }
802803#[test]
804fn test_duration_as_seconds_f64() {
805assert_eq!(TimeDelta::seconds(1).as_seconds_f64(), 1.0);
806assert_eq!(TimeDelta::seconds(-1).as_seconds_f64(), -1.0);
807assert_eq!(TimeDelta::seconds(100).as_seconds_f64(), 100.0);
808assert_eq!(TimeDelta::seconds(-100).as_seconds_f64(), -100.0);
809810assert_eq!(TimeDelta::milliseconds(500).as_seconds_f64(), 0.5);
811assert_eq!(TimeDelta::milliseconds(-500).as_seconds_f64(), -0.5);
812assert_eq!(TimeDelta::milliseconds(1_500).as_seconds_f64(), 1.5);
813assert_eq!(TimeDelta::milliseconds(-1_500).as_seconds_f64(), -1.5);
814 }
815816#[test]
817fn test_duration_as_seconds_f32() {
818assert_eq!(TimeDelta::seconds(1).as_seconds_f32(), 1.0);
819assert_eq!(TimeDelta::seconds(-1).as_seconds_f32(), -1.0);
820assert_eq!(TimeDelta::seconds(100).as_seconds_f32(), 100.0);
821assert_eq!(TimeDelta::seconds(-100).as_seconds_f32(), -100.0);
822823assert_eq!(TimeDelta::milliseconds(500).as_seconds_f32(), 0.5);
824assert_eq!(TimeDelta::milliseconds(-500).as_seconds_f32(), -0.5);
825assert_eq!(TimeDelta::milliseconds(1_500).as_seconds_f32(), 1.5);
826assert_eq!(TimeDelta::milliseconds(-1_500).as_seconds_f32(), -1.5);
827 }
828829#[test]
830fn test_duration_subsec_nanos() {
831assert_eq!(TimeDelta::zero().subsec_nanos(), 0);
832assert_eq!(TimeDelta::nanoseconds(1).subsec_nanos(), 1);
833assert_eq!(TimeDelta::nanoseconds(-1).subsec_nanos(), -1);
834assert_eq!(TimeDelta::seconds(1).subsec_nanos(), 0);
835assert_eq!(TimeDelta::nanoseconds(1_000_000_001).subsec_nanos(), 1);
836 }
837838#[test]
839fn test_duration_subsec_micros() {
840assert_eq!(TimeDelta::zero().subsec_micros(), 0);
841assert_eq!(TimeDelta::microseconds(1).subsec_micros(), 1);
842assert_eq!(TimeDelta::microseconds(-1).subsec_micros(), -1);
843assert_eq!(TimeDelta::seconds(1).subsec_micros(), 0);
844assert_eq!(TimeDelta::microseconds(1_000_001).subsec_micros(), 1);
845assert_eq!(TimeDelta::nanoseconds(1_000_001_999).subsec_micros(), 1);
846 }
847848#[test]
849fn test_duration_subsec_millis() {
850assert_eq!(TimeDelta::zero().subsec_millis(), 0);
851assert_eq!(TimeDelta::milliseconds(1).subsec_millis(), 1);
852assert_eq!(TimeDelta::milliseconds(-1).subsec_millis(), -1);
853assert_eq!(TimeDelta::seconds(1).subsec_millis(), 0);
854assert_eq!(TimeDelta::milliseconds(1_001).subsec_millis(), 1);
855assert_eq!(TimeDelta::microseconds(1_001_999).subsec_millis(), 1);
856 }
857858#[test]
859fn test_duration_num_milliseconds() {
860assert_eq!(TimeDelta::zero().num_milliseconds(), 0);
861assert_eq!(TimeDelta::try_milliseconds(1).unwrap().num_milliseconds(), 1);
862assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().num_milliseconds(), -1);
863assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0);
864assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1);
865assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0);
866assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1);
867 }
868869#[test]
870fn test_duration_milliseconds_max_allowed() {
871// The maximum number of milliseconds acceptable through the constructor is
872 // equal to the number that can be stored in a TimeDelta.
873let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
874assert_eq!(duration.num_milliseconds(), i64::MAX);
875assert_eq!(
876 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
877 i64::MAX as i128 * 1_000_000
878);
879 }
880881#[test]
882fn test_duration_milliseconds_max_overflow() {
883// Here we ensure that trying to add one millisecond to the maximum storable
884 // value will fail.
885assert!(
886 TimeDelta::try_milliseconds(i64::MAX)
887 .unwrap()
888 .checked_add(&TimeDelta::try_milliseconds(1).unwrap())
889 .is_none()
890 );
891 }
892893#[test]
894fn test_duration_milliseconds_min_allowed() {
895// The minimum number of milliseconds acceptable through the constructor is
896 // not equal to the number that can be stored in a TimeDelta - there is a
897 // difference of one (i64::MIN vs -i64::MAX).
898let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
899assert_eq!(duration.num_milliseconds(), -i64::MAX);
900assert_eq!(
901 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
902 -i64::MAX as i128 * 1_000_000
903);
904 }
905906#[test]
907fn test_duration_milliseconds_min_underflow() {
908// Here we ensure that trying to subtract one millisecond from the minimum
909 // storable value will fail.
910assert!(
911 TimeDelta::try_milliseconds(-i64::MAX)
912 .unwrap()
913 .checked_sub(&TimeDelta::try_milliseconds(1).unwrap())
914 .is_none()
915 );
916 }
917918#[test]
919 #[should_panic(expected = "TimeDelta::milliseconds out of bounds")]
920fn test_duration_milliseconds_min_underflow_panic() {
921// Here we ensure that trying to create a value one millisecond below the
922 // minimum storable value will fail. This test is necessary because the
923 // storable range is -i64::MAX, but the constructor type of i64 will allow
924 // i64::MIN, which is one value below.
925let _ = TimeDelta::milliseconds(i64::MIN); // Same as -i64::MAX - 1
926}
927928#[test]
929fn test_duration_num_microseconds() {
930assert_eq!(TimeDelta::zero().num_microseconds(), Some(0));
931assert_eq!(TimeDelta::microseconds(1).num_microseconds(), Some(1));
932assert_eq!(TimeDelta::microseconds(-1).num_microseconds(), Some(-1));
933assert_eq!(TimeDelta::nanoseconds(999).num_microseconds(), Some(0));
934assert_eq!(TimeDelta::nanoseconds(1001).num_microseconds(), Some(1));
935assert_eq!(TimeDelta::nanoseconds(-999).num_microseconds(), Some(0));
936assert_eq!(TimeDelta::nanoseconds(-1001).num_microseconds(), Some(-1));
937938// overflow checks
939const MICROS_PER_DAY: i64 = 86_400_000_000;
940assert_eq!(
941 TimeDelta::try_days(i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
942Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
943 );
944assert_eq!(
945 TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
946Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
947 );
948assert_eq!(
949 TimeDelta::try_days(i64::MAX / MICROS_PER_DAY + 1).unwrap().num_microseconds(),
950None
951);
952assert_eq!(
953 TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY - 1).unwrap().num_microseconds(),
954None
955);
956 }
957#[test]
958fn test_duration_microseconds_max_allowed() {
959// The number of microseconds acceptable through the constructor is far
960 // fewer than the number that can actually be stored in a TimeDelta, so this
961 // is not a particular insightful test.
962let duration = TimeDelta::microseconds(i64::MAX);
963assert_eq!(duration.num_microseconds(), Some(i64::MAX));
964assert_eq!(
965 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
966 i64::MAX as i128 * 1_000
967);
968// Here we create a TimeDelta with the maximum possible number of
969 // microseconds by creating a TimeDelta with the maximum number of
970 // milliseconds and then checking that the number of microseconds matches
971 // the storage limit.
972let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
973assert!(duration.num_microseconds().is_none());
974assert_eq!(
975 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
976 i64::MAX as i128 * 1_000_000
977);
978 }
979#[test]
980fn test_duration_microseconds_max_overflow() {
981// This test establishes that a TimeDelta can store more microseconds than
982 // are representable through the return of duration.num_microseconds().
983let duration = TimeDelta::microseconds(i64::MAX) + TimeDelta::microseconds(1);
984assert!(duration.num_microseconds().is_none());
985assert_eq!(
986 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
987 (i64::MAX as i128 + 1) * 1_000
988);
989// Here we ensure that trying to add one microsecond to the maximum storable
990 // value will fail.
991assert!(
992 TimeDelta::try_milliseconds(i64::MAX)
993 .unwrap()
994 .checked_add(&TimeDelta::microseconds(1))
995 .is_none()
996 );
997 }
998#[test]
999fn test_duration_microseconds_min_allowed() {
1000// The number of microseconds acceptable through the constructor is far
1001 // fewer than the number that can actually be stored in a TimeDelta, so this
1002 // is not a particular insightful test.
1003let duration = TimeDelta::microseconds(i64::MIN);
1004assert_eq!(duration.num_microseconds(), Some(i64::MIN));
1005assert_eq!(
1006 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1007 i64::MIN as i128 * 1_000
1008);
1009// Here we create a TimeDelta with the minimum possible number of
1010 // microseconds by creating a TimeDelta with the minimum number of
1011 // milliseconds and then checking that the number of microseconds matches
1012 // the storage limit.
1013let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
1014assert!(duration.num_microseconds().is_none());
1015assert_eq!(
1016 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1017 -i64::MAX as i128 * 1_000_000
1018);
1019 }
1020#[test]
1021fn test_duration_microseconds_min_underflow() {
1022// This test establishes that a TimeDelta can store more microseconds than
1023 // are representable through the return of duration.num_microseconds().
1024let duration = TimeDelta::microseconds(i64::MIN) - TimeDelta::microseconds(1);
1025assert!(duration.num_microseconds().is_none());
1026assert_eq!(
1027 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1028 (i64::MIN as i128 - 1) * 1_000
1029);
1030// Here we ensure that trying to subtract one microsecond from the minimum
1031 // storable value will fail.
1032assert!(
1033 TimeDelta::try_milliseconds(-i64::MAX)
1034 .unwrap()
1035 .checked_sub(&TimeDelta::microseconds(1))
1036 .is_none()
1037 );
1038 }
10391040#[test]
1041fn test_duration_num_nanoseconds() {
1042assert_eq!(TimeDelta::zero().num_nanoseconds(), Some(0));
1043assert_eq!(TimeDelta::nanoseconds(1).num_nanoseconds(), Some(1));
1044assert_eq!(TimeDelta::nanoseconds(-1).num_nanoseconds(), Some(-1));
10451046// overflow checks
1047const NANOS_PER_DAY: i64 = 86_400_000_000_000;
1048assert_eq!(
1049 TimeDelta::try_days(i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
1050Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
1051 );
1052assert_eq!(
1053 TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
1054Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
1055 );
1056assert_eq!(
1057 TimeDelta::try_days(i64::MAX / NANOS_PER_DAY + 1).unwrap().num_nanoseconds(),
1058None
1059);
1060assert_eq!(
1061 TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY - 1).unwrap().num_nanoseconds(),
1062None
1063);
1064 }
1065#[test]
1066fn test_duration_nanoseconds_max_allowed() {
1067// The number of nanoseconds acceptable through the constructor is far fewer
1068 // than the number that can actually be stored in a TimeDelta, so this is not
1069 // a particular insightful test.
1070let duration = TimeDelta::nanoseconds(i64::MAX);
1071assert_eq!(duration.num_nanoseconds(), Some(i64::MAX));
1072assert_eq!(
1073 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1074 i64::MAX as i128
1075 );
1076// Here we create a TimeDelta with the maximum possible number of nanoseconds
1077 // by creating a TimeDelta with the maximum number of milliseconds and then
1078 // checking that the number of nanoseconds matches the storage limit.
1079let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
1080assert!(duration.num_nanoseconds().is_none());
1081assert_eq!(
1082 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1083 i64::MAX as i128 * 1_000_000
1084);
1085 }
10861087#[test]
1088fn test_duration_nanoseconds_max_overflow() {
1089// This test establishes that a TimeDelta can store more nanoseconds than are
1090 // representable through the return of duration.num_nanoseconds().
1091let duration = TimeDelta::nanoseconds(i64::MAX) + TimeDelta::nanoseconds(1);
1092assert!(duration.num_nanoseconds().is_none());
1093assert_eq!(
1094 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1095 i64::MAX as i128 + 1
1096);
1097// Here we ensure that trying to add one nanosecond to the maximum storable
1098 // value will fail.
1099assert!(
1100 TimeDelta::try_milliseconds(i64::MAX)
1101 .unwrap()
1102 .checked_add(&TimeDelta::nanoseconds(1))
1103 .is_none()
1104 );
1105 }
11061107#[test]
1108fn test_duration_nanoseconds_min_allowed() {
1109// The number of nanoseconds acceptable through the constructor is far fewer
1110 // than the number that can actually be stored in a TimeDelta, so this is not
1111 // a particular insightful test.
1112let duration = TimeDelta::nanoseconds(i64::MIN);
1113assert_eq!(duration.num_nanoseconds(), Some(i64::MIN));
1114assert_eq!(
1115 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1116 i64::MIN as i128
1117 );
1118// Here we create a TimeDelta with the minimum possible number of nanoseconds
1119 // by creating a TimeDelta with the minimum number of milliseconds and then
1120 // checking that the number of nanoseconds matches the storage limit.
1121let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
1122assert!(duration.num_nanoseconds().is_none());
1123assert_eq!(
1124 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1125 -i64::MAX as i128 * 1_000_000
1126);
1127 }
11281129#[test]
1130fn test_duration_nanoseconds_min_underflow() {
1131// This test establishes that a TimeDelta can store more nanoseconds than are
1132 // representable through the return of duration.num_nanoseconds().
1133let duration = TimeDelta::nanoseconds(i64::MIN) - TimeDelta::nanoseconds(1);
1134assert!(duration.num_nanoseconds().is_none());
1135assert_eq!(
1136 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1137 i64::MIN as i128 - 1
1138);
1139// Here we ensure that trying to subtract one nanosecond from the minimum
1140 // storable value will fail.
1141assert!(
1142 TimeDelta::try_milliseconds(-i64::MAX)
1143 .unwrap()
1144 .checked_sub(&TimeDelta::nanoseconds(1))
1145 .is_none()
1146 );
1147 }
11481149#[test]
1150fn test_max() {
1151assert_eq!(
1152 MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128,
1153 i64::MAX as i128 * 1_000_000
1154);
1155assert_eq!(MAX, TimeDelta::try_milliseconds(i64::MAX).unwrap());
1156assert_eq!(MAX.num_milliseconds(), i64::MAX);
1157assert_eq!(MAX.num_microseconds(), None);
1158assert_eq!(MAX.num_nanoseconds(), None);
1159 }
11601161#[test]
1162fn test_min() {
1163assert_eq!(
1164 MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128,
1165 -i64::MAX as i128 * 1_000_000
1166);
1167assert_eq!(MIN, TimeDelta::try_milliseconds(-i64::MAX).unwrap());
1168assert_eq!(MIN.num_milliseconds(), -i64::MAX);
1169assert_eq!(MIN.num_microseconds(), None);
1170assert_eq!(MIN.num_nanoseconds(), None);
1171 }
11721173#[test]
1174fn test_duration_ord() {
1175let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
11761177assert!(milliseconds(1) < milliseconds(2));
1178assert!(milliseconds(2) > milliseconds(1));
1179assert!(milliseconds(-1) > milliseconds(-2));
1180assert!(milliseconds(-2) < milliseconds(-1));
1181assert!(milliseconds(-1) < milliseconds(1));
1182assert!(milliseconds(1) > milliseconds(-1));
1183assert!(milliseconds(0) < milliseconds(1));
1184assert!(milliseconds(0) > milliseconds(-1));
1185assert!(milliseconds(1_001) < milliseconds(1_002));
1186assert!(milliseconds(-1_001) > milliseconds(-1_002));
1187assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891));
1188assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891));
1189assert!(milliseconds(i64::MAX) > milliseconds(i64::MAX - 1));
1190assert!(milliseconds(-i64::MAX) < milliseconds(-i64::MAX + 1));
1191 }
11921193#[test]
1194fn test_duration_checked_ops() {
1195let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1196let seconds = |s| TimeDelta::try_seconds(s).unwrap();
11971198assert_eq!(
1199 milliseconds(i64::MAX).checked_add(&milliseconds(0)),
1200Some(milliseconds(i64::MAX))
1201 );
1202assert_eq!(
1203 milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
1204Some(milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
1205 );
1206assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::microseconds(1000)).is_none());
1207assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::nanoseconds(1)).is_none());
12081209assert_eq!(
1210 milliseconds(-i64::MAX).checked_sub(&milliseconds(0)),
1211Some(milliseconds(-i64::MAX))
1212 );
1213assert_eq!(
1214 milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
1215Some(milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
1216 );
1217assert!(milliseconds(-i64::MAX).checked_sub(&milliseconds(1)).is_none());
1218assert!(milliseconds(-i64::MAX).checked_sub(&TimeDelta::nanoseconds(1)).is_none());
12191220assert!(seconds(i64::MAX / 1000).checked_mul(2000).is_none());
1221assert!(seconds(i64::MIN / 1000).checked_mul(2000).is_none());
1222assert!(seconds(1).checked_div(0).is_none());
1223 }
12241225#[test]
1226fn test_duration_abs() {
1227let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
12281229assert_eq!(milliseconds(1300).abs(), milliseconds(1300));
1230assert_eq!(milliseconds(1000).abs(), milliseconds(1000));
1231assert_eq!(milliseconds(300).abs(), milliseconds(300));
1232assert_eq!(milliseconds(0).abs(), milliseconds(0));
1233assert_eq!(milliseconds(-300).abs(), milliseconds(300));
1234assert_eq!(milliseconds(-700).abs(), milliseconds(700));
1235assert_eq!(milliseconds(-1000).abs(), milliseconds(1000));
1236assert_eq!(milliseconds(-1300).abs(), milliseconds(1300));
1237assert_eq!(milliseconds(-1700).abs(), milliseconds(1700));
1238assert_eq!(milliseconds(-i64::MAX).abs(), milliseconds(i64::MAX));
1239 }
12401241#[test]
1242 #[allow(clippy::erasing_op)]
1243fn test_duration_mul() {
1244assert_eq!(TimeDelta::zero() * i32::MAX, TimeDelta::zero());
1245assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero());
1246assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero());
1247assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1));
1248assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::try_seconds(1).unwrap());
1249assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1250assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1251assert_eq!(
1252 TimeDelta::nanoseconds(30) * 333_333_333,
1253 TimeDelta::try_seconds(10).unwrap() - TimeDelta::nanoseconds(10)
1254 );
1255assert_eq!(
1256 (TimeDelta::nanoseconds(1)
1257 + TimeDelta::try_seconds(1).unwrap()
1258 + TimeDelta::try_days(1).unwrap())
1259 * 3,
1260 TimeDelta::nanoseconds(3)
1261 + TimeDelta::try_seconds(3).unwrap()
1262 + TimeDelta::try_days(3).unwrap()
1263 );
1264assert_eq!(
1265 TimeDelta::try_milliseconds(1500).unwrap() * -2,
1266 TimeDelta::try_seconds(-3).unwrap()
1267 );
1268assert_eq!(
1269 TimeDelta::try_milliseconds(-1500).unwrap() * 2,
1270 TimeDelta::try_seconds(-3).unwrap()
1271 );
1272 }
12731274#[test]
1275fn test_duration_div() {
1276assert_eq!(TimeDelta::zero() / i32::MAX, TimeDelta::zero());
1277assert_eq!(TimeDelta::zero() / i32::MIN, TimeDelta::zero());
1278assert_eq!(TimeDelta::nanoseconds(123_456_789) / 1, TimeDelta::nanoseconds(123_456_789));
1279assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789));
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::try_seconds(1).unwrap() / 3, TimeDelta::nanoseconds(333_333_333));
1283assert_eq!(TimeDelta::try_seconds(4).unwrap() / 3, TimeDelta::nanoseconds(1_333_333_333));
1284assert_eq!(
1285 TimeDelta::try_seconds(-1).unwrap() / 2,
1286 TimeDelta::try_milliseconds(-500).unwrap()
1287 );
1288assert_eq!(
1289 TimeDelta::try_seconds(1).unwrap() / -2,
1290 TimeDelta::try_milliseconds(-500).unwrap()
1291 );
1292assert_eq!(
1293 TimeDelta::try_seconds(-1).unwrap() / -2,
1294 TimeDelta::try_milliseconds(500).unwrap()
1295 );
1296assert_eq!(TimeDelta::try_seconds(-4).unwrap() / 3, TimeDelta::nanoseconds(-1_333_333_333));
1297assert_eq!(TimeDelta::try_seconds(-4).unwrap() / -3, TimeDelta::nanoseconds(1_333_333_333));
1298 }
12991300#[test]
1301fn test_duration_sum() {
1302let duration_list_1 = [TimeDelta::zero(), TimeDelta::try_seconds(1).unwrap()];
1303let sum_1: TimeDelta = duration_list_1.iter().sum();
1304assert_eq!(sum_1, TimeDelta::try_seconds(1).unwrap());
13051306let duration_list_2 = [
1307 TimeDelta::zero(),
1308 TimeDelta::try_seconds(1).unwrap(),
1309 TimeDelta::try_seconds(6).unwrap(),
1310 TimeDelta::try_seconds(10).unwrap(),
1311 ];
1312let sum_2: TimeDelta = duration_list_2.iter().sum();
1313assert_eq!(sum_2, TimeDelta::try_seconds(17).unwrap());
13141315let duration_arr = [
1316 TimeDelta::zero(),
1317 TimeDelta::try_seconds(1).unwrap(),
1318 TimeDelta::try_seconds(6).unwrap(),
1319 TimeDelta::try_seconds(10).unwrap(),
1320 ];
1321let sum_3: TimeDelta = duration_arr.into_iter().sum();
1322assert_eq!(sum_3, TimeDelta::try_seconds(17).unwrap());
1323 }
13241325#[test]
1326fn test_duration_fmt() {
1327assert_eq!(TimeDelta::zero().to_string(), "P0D");
1328assert_eq!(TimeDelta::try_days(42).unwrap().to_string(), "PT3628800S");
1329assert_eq!(TimeDelta::try_days(-42).unwrap().to_string(), "-PT3628800S");
1330assert_eq!(TimeDelta::try_seconds(42).unwrap().to_string(), "PT42S");
1331assert_eq!(TimeDelta::try_milliseconds(42).unwrap().to_string(), "PT0.042S");
1332assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S");
1333assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S");
1334assert_eq!(
1335 (TimeDelta::try_days(7).unwrap() + TimeDelta::try_milliseconds(6543).unwrap())
1336 .to_string(),
1337"PT604806.543S"
1338);
1339assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().to_string(), "-PT86401S");
1340assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S");
13411342// the format specifier should have no effect on `TimeDelta`
1343assert_eq!(
1344format!(
1345"{:30}",
1346 TimeDelta::try_days(1).unwrap() + TimeDelta::try_milliseconds(2345).unwrap()
1347 ),
1348"PT86402.345S"
1349);
1350 }
13511352#[test]
1353fn test_to_std() {
1354assert_eq!(TimeDelta::try_seconds(1).unwrap().to_std(), Ok(Duration::new(1, 0)));
1355assert_eq!(TimeDelta::try_seconds(86_401).unwrap().to_std(), Ok(Duration::new(86_401, 0)));
1356assert_eq!(
1357 TimeDelta::try_milliseconds(123).unwrap().to_std(),
1358Ok(Duration::new(0, 123_000_000))
1359 );
1360assert_eq!(
1361 TimeDelta::try_milliseconds(123_765).unwrap().to_std(),
1362Ok(Duration::new(123, 765_000_000))
1363 );
1364assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777)));
1365assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000)));
1366assert_eq!(TimeDelta::try_seconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1367assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1368 }
13691370#[test]
1371fn test_from_std() {
1372assert_eq!(
1373Ok(TimeDelta::try_seconds(1).unwrap()),
1374 TimeDelta::from_std(Duration::new(1, 0))
1375 );
1376assert_eq!(
1377Ok(TimeDelta::try_seconds(86_401).unwrap()),
1378 TimeDelta::from_std(Duration::new(86_401, 0))
1379 );
1380assert_eq!(
1381Ok(TimeDelta::try_milliseconds(123).unwrap()),
1382 TimeDelta::from_std(Duration::new(0, 123_000_000))
1383 );
1384assert_eq!(
1385Ok(TimeDelta::try_milliseconds(123_765).unwrap()),
1386 TimeDelta::from_std(Duration::new(123, 765_000_000))
1387 );
1388assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777)));
1389assert_eq!(Ok(MAX), TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_000)));
1390assert_eq!(
1391 TimeDelta::from_std(Duration::new(9_223_372_036_854_776, 0)),
1392Err(OutOfRangeError(()))
1393 );
1394assert_eq!(
1395 TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_001)),
1396Err(OutOfRangeError(()))
1397 );
1398 }
13991400#[test]
1401fn test_duration_const() {
1402const ONE_WEEK: TimeDelta = expect(TimeDelta::try_weeks(1), "");
1403const ONE_DAY: TimeDelta = expect(TimeDelta::try_days(1), "");
1404const ONE_HOUR: TimeDelta = expect(TimeDelta::try_hours(1), "");
1405const ONE_MINUTE: TimeDelta = expect(TimeDelta::try_minutes(1), "");
1406const ONE_SECOND: TimeDelta = expect(TimeDelta::try_seconds(1), "");
1407const ONE_MILLI: TimeDelta = expect(TimeDelta::try_milliseconds(1), "");
1408const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1);
1409const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1);
1410let combo: TimeDelta = ONE_WEEK
1411 + ONE_DAY
1412 + ONE_HOUR
1413 + ONE_MINUTE
1414 + ONE_SECOND
1415 + ONE_MILLI
1416 + ONE_MICRO
1417 + ONE_NANO;
14181419assert!(ONE_WEEK != TimeDelta::zero());
1420assert!(ONE_DAY != TimeDelta::zero());
1421assert!(ONE_HOUR != TimeDelta::zero());
1422assert!(ONE_MINUTE != TimeDelta::zero());
1423assert!(ONE_SECOND != TimeDelta::zero());
1424assert!(ONE_MILLI != TimeDelta::zero());
1425assert!(ONE_MICRO != TimeDelta::zero());
1426assert!(ONE_NANO != TimeDelta::zero());
1427assert_eq!(
1428 combo,
1429 TimeDelta::try_seconds(86400 * 7 + 86400 + 3600 + 60 + 1).unwrap()
1430 + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000)
1431 );
1432 }
14331434#[test]
1435 #[cfg(feature = "rkyv-validation")]
1436fn test_rkyv_validation() {
1437let duration = TimeDelta::try_seconds(1).unwrap();
1438let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
1439assert_eq!(rkyv::from_bytes::<TimeDelta>(&bytes).unwrap(), duration);
1440 }
1441}