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]
108 #[track_caller]
109pub const fn weeks(weeks: i64) -> TimeDelta {
110expect(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds")
111 }
112113/// Makes a new `TimeDelta` with the given number of weeks.
114 ///
115 /// Equivalent to `TimeDelta::try_seconds(weeks * 7 * 24 * 60 * 60)` with
116 /// overflow checks.
117 ///
118 /// # Errors
119 ///
120 /// Returns `None` when the `TimeDelta` would be out of bounds.
121#[inline]
122pub const fn try_weeks(weeks: i64) -> Option<TimeDelta> {
123TimeDelta::try_seconds(match weeks.checked_mul(SECS_PER_WEEK) { Some(v) => v, None => return None, }try_opt!(weeks.checked_mul(SECS_PER_WEEK)))
124 }
125126/// Makes a new `TimeDelta` with the given number of days.
127 ///
128 /// Equivalent to `TimeDelta::seconds(days * 24 * 60 * 60)` with overflow
129 /// checks.
130 ///
131 /// # Panics
132 ///
133 /// Panics when the `TimeDelta` would be out of bounds.
134#[inline]
135 #[must_use]
136 #[track_caller]
137pub const fn days(days: i64) -> TimeDelta {
138expect(TimeDelta::try_days(days), "TimeDelta::days out of bounds")
139 }
140141/// Makes a new `TimeDelta` with the given number of days.
142 ///
143 /// Equivalent to `TimeDelta::try_seconds(days * 24 * 60 * 60)` with overflow
144 /// checks.
145 ///
146 /// # Errors
147 ///
148 /// Returns `None` when the `TimeDelta` would be out of bounds.
149#[inline]
150pub const fn try_days(days: i64) -> Option<TimeDelta> {
151TimeDelta::try_seconds(match days.checked_mul(SECS_PER_DAY) { Some(v) => v, None => return None, }try_opt!(days.checked_mul(SECS_PER_DAY)))
152 }
153154/// Makes a new `TimeDelta` with the given number of hours.
155 ///
156 /// Equivalent to `TimeDelta::seconds(hours * 60 * 60)` with overflow checks.
157 ///
158 /// # Panics
159 ///
160 /// Panics when the `TimeDelta` would be out of bounds.
161#[inline]
162 #[must_use]
163 #[track_caller]
164pub const fn hours(hours: i64) -> TimeDelta {
165expect(TimeDelta::try_hours(hours), "TimeDelta::hours out of bounds")
166 }
167168/// Makes a new `TimeDelta` with the given number of hours.
169 ///
170 /// Equivalent to `TimeDelta::try_seconds(hours * 60 * 60)` with overflow checks.
171 ///
172 /// # Errors
173 ///
174 /// Returns `None` when the `TimeDelta` would be out of bounds.
175#[inline]
176pub const fn try_hours(hours: i64) -> Option<TimeDelta> {
177TimeDelta::try_seconds(match hours.checked_mul(SECS_PER_HOUR) { Some(v) => v, None => return None, }try_opt!(hours.checked_mul(SECS_PER_HOUR)))
178 }
179180/// Makes a new `TimeDelta` with the given number of minutes.
181 ///
182 /// Equivalent to `TimeDelta::seconds(minutes * 60)` with overflow checks.
183 ///
184 /// # Panics
185 ///
186 /// Panics when the `TimeDelta` would be out of bounds.
187#[inline]
188 #[must_use]
189 #[track_caller]
190pub const fn minutes(minutes: i64) -> TimeDelta {
191expect(TimeDelta::try_minutes(minutes), "TimeDelta::minutes out of bounds")
192 }
193194/// Makes a new `TimeDelta` with the given number of minutes.
195 ///
196 /// Equivalent to `TimeDelta::try_seconds(minutes * 60)` with overflow checks.
197 ///
198 /// # Errors
199 ///
200 /// Returns `None` when the `TimeDelta` would be out of bounds.
201#[inline]
202pub const fn try_minutes(minutes: i64) -> Option<TimeDelta> {
203TimeDelta::try_seconds(match minutes.checked_mul(SECS_PER_MINUTE) {
Some(v) => v,
None => return None,
}try_opt!(minutes.checked_mul(SECS_PER_MINUTE)))
204 }
205206/// Makes a new `TimeDelta` with the given number of seconds.
207 ///
208 /// # Panics
209 ///
210 /// Panics when `seconds` is more than `i64::MAX / 1_000` or less than `-i64::MAX / 1_000`
211 /// (in this context, this is the same as `i64::MIN / 1_000` due to rounding).
212#[inline]
213 #[must_use]
214 #[track_caller]
215pub const fn seconds(seconds: i64) -> TimeDelta {
216expect(TimeDelta::try_seconds(seconds), "TimeDelta::seconds out of bounds")
217 }
218219/// Makes a new `TimeDelta` with the given number of seconds.
220 ///
221 /// # Errors
222 ///
223 /// Returns `None` when `seconds` is more than `i64::MAX / 1_000` or less than
224 /// `-i64::MAX / 1_000` (in this context, this is the same as `i64::MIN / 1_000` due to
225 /// rounding).
226#[inline]
227pub const fn try_seconds(seconds: i64) -> Option<TimeDelta> {
228TimeDelta::new(seconds, 0)
229 }
230231/// Makes a new `TimeDelta` with the given number of milliseconds.
232 ///
233 /// # Panics
234 ///
235 /// Panics when the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more than
236 /// `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
237#[inline]
238 #[track_caller]
239pub const fn milliseconds(milliseconds: i64) -> TimeDelta {
240expect(TimeDelta::try_milliseconds(milliseconds), "TimeDelta::milliseconds out of bounds")
241 }
242243/// Makes a new `TimeDelta` with the given number of milliseconds.
244 ///
245 /// # Errors
246 ///
247 /// Returns `None` the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more
248 /// than `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
249#[inline]
250pub const fn try_milliseconds(milliseconds: i64) -> Option<TimeDelta> {
251// We don't need to compare against MAX, as this function accepts an
252 // i64, and MAX is aligned to i64::MAX milliseconds.
253if milliseconds < -i64::MAX {
254return None;
255 }
256let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
257let d = TimeDelta { secs, nanos: millisas i32 * NANOS_PER_MILLI };
258Some(d)
259 }
260261/// Makes a new `TimeDelta` with the given number of microseconds.
262 ///
263 /// The number of microseconds acceptable by this constructor is less than
264 /// the total number that can actually be stored in a `TimeDelta`, so it is
265 /// not possible to specify a value that would be out of bounds. This
266 /// function is therefore infallible.
267#[inline]
268pub const fn microseconds(microseconds: i64) -> TimeDelta {
269let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
270let nanos = microsas i32 * NANOS_PER_MICRO;
271TimeDelta { secs, nanos }
272 }
273274/// Makes a new `TimeDelta` with the given number of nanoseconds.
275 ///
276 /// The number of nanoseconds acceptable by this constructor is less than
277 /// the total number that can actually be stored in a `TimeDelta`, so it is
278 /// not possible to specify a value that would be out of bounds. This
279 /// function is therefore infallible.
280#[inline]
281pub const fn nanoseconds(nanos: i64) -> TimeDelta {
282let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SECas i64);
283TimeDelta { secs, nanos: nanosas i32 }
284 }
285286/// Returns the total number of whole weeks in the `TimeDelta`.
287#[inline]
288pub const fn num_weeks(&self) -> i64 {
289self.num_days() / 7
290}
291292/// Returns the total number of whole days in the `TimeDelta`.
293#[inline]
294pub const fn num_days(&self) -> i64 {
295self.num_seconds() / SECS_PER_DAY296 }
297298/// Returns the total number of whole hours in the `TimeDelta`.
299#[inline]
300pub const fn num_hours(&self) -> i64 {
301self.num_seconds() / SECS_PER_HOUR302 }
303304/// Returns the total number of whole minutes in the `TimeDelta`.
305#[inline]
306pub const fn num_minutes(&self) -> i64 {
307self.num_seconds() / SECS_PER_MINUTE308 }
309310/// Returns the total number of whole seconds in the `TimeDelta`.
311pub const fn num_seconds(&self) -> i64 {
312// If secs is negative, nanos should be subtracted from the duration.
313if self.secs < 0 && self.nanos > 0 { self.secs + 1 } else { self.secs }
314 }
315316/// Returns the fractional number of seconds in the `TimeDelta`.
317pub fn as_seconds_f64(self) -> f64 {
318self.secs as f64 + self.nanos as f64 / NANOS_PER_SECas f64319 }
320321/// Returns the fractional number of seconds in the `TimeDelta`.
322pub fn as_seconds_f32(self) -> f32 {
323self.secs as f32 + self.nanos as f32 / NANOS_PER_SECas f32324 }
325326/// Returns the total number of whole milliseconds in the `TimeDelta`.
327pub const fn num_milliseconds(&self) -> i64 {
328// A proper TimeDelta will not overflow, because MIN and MAX are defined such
329 // that the range is within the bounds of an i64, from -i64::MAX through to
330 // +i64::MAX inclusive. Notably, i64::MIN is excluded from this range.
331let secs_part = self.num_seconds() * MILLIS_PER_SEC;
332let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI;
333secs_part + nanos_partas i64334 }
335336/// Returns the number of milliseconds in the fractional part of the duration.
337 ///
338 /// This is the number of milliseconds such that
339 /// `subsec_millis() + num_seconds() * 1_000` is the truncated number of
340 /// milliseconds in the duration.
341pub const fn subsec_millis(&self) -> i32 {
342self.subsec_nanos() / NANOS_PER_MILLI343 }
344345/// Returns the total number of whole microseconds in the `TimeDelta`,
346 /// or `None` on overflow (exceeding 2^63 microseconds in either direction).
347pub const fn num_microseconds(&self) -> Option<i64> {
348let 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));
349let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO;
350secs_part.checked_add(nanos_partas i64)
351 }
352353/// Returns the number of microseconds in the fractional part of the duration.
354 ///
355 /// This is the number of microseconds such that
356 /// `subsec_micros() + num_seconds() * 1_000_000` is the truncated number of
357 /// microseconds in the duration.
358pub const fn subsec_micros(&self) -> i32 {
359self.subsec_nanos() / NANOS_PER_MICRO360 }
361362/// Returns the total number of whole nanoseconds in the `TimeDelta`,
363 /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
364pub const fn num_nanoseconds(&self) -> Option<i64> {
365let 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));
366let nanos_part = self.subsec_nanos();
367secs_part.checked_add(nanos_partas i64)
368 }
369370/// Returns the number of nanoseconds in the fractional part of the duration.
371 ///
372 /// This is the number of nanoseconds such that
373 /// `subsec_nanos() + num_seconds() * 1_000_000_000` is the total number of
374 /// nanoseconds in the `TimeDelta`.
375pub const fn subsec_nanos(&self) -> i32 {
376if self.secs < 0 && self.nanos > 0 { self.nanos - NANOS_PER_SEC } else { self.nanos }
377 }
378379/// Add two `TimeDelta`s, returning `None` if overflow occurred.
380#[must_use]
381pub const fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
382// No overflow checks here because we stay comfortably within the range of an `i64`.
383 // Range checks happen in `TimeDelta::new`.
384let mut secs = self.secs + rhs.secs;
385let mut nanos = self.nanos + rhs.nanos;
386if nanos >= NANOS_PER_SEC {
387nanos -= NANOS_PER_SEC;
388secs += 1;
389 }
390TimeDelta::new(secs, nanosas u32)
391 }
392393/// Subtract two `TimeDelta`s, returning `None` if overflow occurred.
394#[must_use]
395pub const fn checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
396// No overflow checks here because we stay comfortably within the range of an `i64`.
397 // Range checks happen in `TimeDelta::new`.
398let mut secs = self.secs - rhs.secs;
399let mut nanos = self.nanos - rhs.nanos;
400if nanos < 0 {
401nanos += NANOS_PER_SEC;
402secs -= 1;
403 }
404TimeDelta::new(secs, nanosas u32)
405 }
406407/// Multiply a `TimeDelta` with a i32, returning `None` if overflow occurred.
408#[must_use]
409pub const fn checked_mul(&self, rhs: i32) -> Option<TimeDelta> {
410// Multiply nanoseconds as i64, because it cannot overflow that way.
411let total_nanos = self.nanos as i64 * rhsas i64;
412let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SECas i64);
413// Multiply seconds as i128 to prevent overflow
414let secs: i128 = self.secs as i128 * rhsas i128 + extra_secsas i128;
415if secs <= i64::MINas i128 || secs >= i64::MAXas i128 {
416return None;
417 };
418Some(TimeDelta { secs: secsas i64, nanos: nanosas i32 })
419 }
420421/// Divide a `TimeDelta` with a i32, returning `None` if dividing by 0.
422#[must_use]
423pub const fn checked_div(&self, rhs: i32) -> Option<TimeDelta> {
424if rhs == 0 {
425return None;
426 }
427let secs = self.secs / rhsas i64;
428let carry = self.secs % rhsas i64;
429let extra_nanos = carry * NANOS_PER_SECas i64 / rhsas i64;
430let nanos = self.nanos / rhs + extra_nanosas i32;
431432let (secs, nanos) = match nanos {
433i32::MIN..=-1 => (secs - 1, nanos + NANOS_PER_SEC),
434NANOS_PER_SEC..=i32::MAX => (secs + 1, nanos - NANOS_PER_SEC),
435_ => (secs, nanos),
436 };
437438Some(TimeDelta { secs, nanos })
439 }
440441/// Returns the `TimeDelta` as an absolute (non-negative) value.
442#[inline]
443pub const fn abs(&self) -> TimeDelta {
444if self.secs < 0 && self.nanos != 0 {
445TimeDelta { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos }
446 } else {
447TimeDelta { secs: self.secs.abs(), nanos: self.nanos }
448 }
449 }
450451/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
452#[deprecated(since = "0.4.39", note = "Use `TimeDelta::MIN` instead")]
453 #[inline]
454pub const fn min_value() -> TimeDelta {
455MIN456 }
457458/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
459#[deprecated(since = "0.4.39", note = "Use `TimeDelta::MAX` instead")]
460 #[inline]
461pub const fn max_value() -> TimeDelta {
462MAX463 }
464465/// A `TimeDelta` where the stored seconds and nanoseconds are equal to zero.
466#[inline]
467pub const fn zero() -> TimeDelta {
468TimeDelta { secs: 0, nanos: 0 }
469 }
470471/// Returns `true` if the `TimeDelta` equals `TimeDelta::zero()`.
472#[inline]
473pub const fn is_zero(&self) -> bool {
474self.secs == 0 && self.nanos == 0
475}
476477/// Creates a `TimeDelta` object from `std::time::Duration`
478 ///
479 /// This function errors when original duration is larger than the maximum
480 /// value supported for this type.
481pub const fn from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError> {
482// We need to check secs as u64 before coercing to i64
483if duration.as_secs() > MAX.secs as u64 {
484return Err(OutOfRangeError(()));
485 }
486match TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos()) {
487Some(d) => Ok(d),
488None => Err(OutOfRangeError(())),
489 }
490 }
491492/// Creates a `std::time::Duration` object from a `TimeDelta`.
493 ///
494 /// This function errors when duration is less than zero. As standard
495 /// library implementation is limited to non-negative values.
496pub const fn to_std(&self) -> Result<Duration, OutOfRangeError> {
497if self.secs < 0 {
498return Err(OutOfRangeError(()));
499 }
500Ok(Duration::new(self.secs as u64, self.nanos as u32))
501 }
502503/// This duplicates `Neg::neg` because trait methods can't be const yet.
504pub(crate) const fn neg(self) -> TimeDelta {
505let (secs_diff, nanos) = match self.nanos {
5060 => (0, 0),
507 nanos => (1, NANOS_PER_SEC - nanos),
508 };
509TimeDelta { secs: -self.secs - secs_diff, nanos }
510 }
511512/// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
513pub const MIN: Self = MIN;
514515/// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
516pub const MAX: Self = MAX;
517}
518519impl Negfor TimeDelta {
520type Output = TimeDelta;
521522#[inline]
523 #[track_caller]
524fn neg(self) -> TimeDelta {
525let (secs_diff, nanos) = match self.nanos {
5260 => (0, 0),
527 nanos => (1, NANOS_PER_SEC - nanos),
528 };
529TimeDelta { secs: -self.secs - secs_diff, nanos }
530 }
531}
532533impl Addfor TimeDelta {
534type Output = TimeDelta;
535536#[track_caller]
537fn add(self, rhs: TimeDelta) -> TimeDelta {
538self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed")
539 }
540}
541542impl Subfor TimeDelta {
543type Output = TimeDelta;
544545#[track_caller]
546fn sub(self, rhs: TimeDelta) -> TimeDelta {
547self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed")
548 }
549}
550551impl AddAssignfor TimeDelta {
552#[track_caller]
553fn add_assign(&mut self, rhs: TimeDelta) {
554let new = self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed");
555*self = new;
556 }
557}
558559impl SubAssignfor TimeDelta {
560#[track_caller]
561fn sub_assign(&mut self, rhs: TimeDelta) {
562let new = self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed");
563*self = new;
564 }
565}
566567impl Mul<i32> for TimeDelta {
568type Output = TimeDelta;
569570#[track_caller]
571fn mul(self, rhs: i32) -> TimeDelta {
572self.checked_mul(rhs).expect("`TimeDelta * i32` overflowed")
573 }
574}
575576impl Div<i32> for TimeDelta {
577type Output = TimeDelta;
578579#[track_caller]
580fn div(self, rhs: i32) -> TimeDelta {
581self.checked_div(rhs).expect("`i32` is zero")
582 }
583}
584585impl<'a> core::iter::Sum<&'a TimeDelta> for TimeDelta {
586fn sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta {
587iter.fold(TimeDelta::zero(), |acc, x| acc + *x)
588 }
589}
590591impl core::iter::Sum<TimeDelta> for TimeDelta {
592fn sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta {
593iter.fold(TimeDelta::zero(), |acc, x| acc + x)
594 }
595}
596597impl fmt::Displayfor TimeDelta {
598/// Format a `TimeDelta` using the [ISO 8601] format
599 ///
600 /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601#Durations
601fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
602// technically speaking, negative duration is not valid ISO 8601,
603 // but we need to print it anyway.
604let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
605606f.write_fmt(format_args!("{0}P", sign))write!(f, "{sign}P")?;
607// Plenty of ways to encode an empty string. `P0D` is short and not too strange.
608if abs.secs == 0 && abs.nanos == 0 {
609return f.write_str("0D");
610 }
611612f.write_fmt(format_args!("T{0}", abs.secs)format_args!("T{}", abs.secs))?;
613614if abs.nanos > 0 {
615// Count the number of significant digits, while removing all trailing zero's.
616let mut figures = 9usize;
617let mut fraction_digits = abs.nanos;
618loop {
619let div = fraction_digits / 10;
620let last_digit = fraction_digits % 10;
621if last_digit != 0 {
622break;
623 }
624fraction_digits = div;
625figures -= 1;
626 }
627f.write_fmt(format_args!(".{0:01$}", fraction_digits, figures)format_args!(".{fraction_digits:0figures$}"))?;
628 }
629f.write_str("S")?;
630Ok(())
631 }
632}
633634/// Represents error when converting `TimeDelta` to/from a standard library
635/// implementation
636///
637/// The `std::time::Duration` supports a range from zero to `u64::MAX`
638/// *seconds*, while this module supports signed range of up to
639/// `i64::MAX` of *milliseconds*.
640#[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)]
641#[cfg_attr(feature = "defmt", derive(defmt::Format))]
642pub struct OutOfRangeError(());
643644impl fmt::Displayfor OutOfRangeError {
645fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
646f.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")647 }
648}
649650#[cfg(any(feature = "std", feature = "core-error"))]
651impl Errorfor OutOfRangeError {
652#[allow(deprecated)]
653fn description(&self) -> &str {
654"out of range error"
655}
656}
657658#[inline]
659const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
660 (this.div_euclid(other), this.rem_euclid(other))
661}
662663#[cfg(all(feature = "arbitrary", feature = "std"))]
664impl arbitrary::Arbitrary<'_> for TimeDelta {
665fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta> {
666const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1;
667const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
668669let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
670let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?;
671let duration = TimeDelta { secs, nanos };
672673if duration < MIN || duration > MAX {
674Err(arbitrary::Error::IncorrectFormat)
675 } else {
676Ok(duration)
677 }
678 }
679}
680681#[cfg(feature = "serde")]
682mod serde {
683use super::TimeDelta;
684use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error};
685686impl Serialize for TimeDelta {
687fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
688 <(i64, i32) as Serialize>::serialize(&(self.secs, self.nanos), serializer)
689 }
690 }
691692impl<'de> Deserialize<'de> for TimeDelta {
693fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
694let (secs, nanos) = <(i64, i32) as Deserialize>::deserialize(deserializer)?;
695 TimeDelta::new(secs, nanos as u32).ok_or(Error::custom("TimeDelta out of bounds"))
696 }
697 }
698699#[cfg(test)]
700mod tests {
701use super::{super::MAX, TimeDelta};
702703#[test]
704fn test_serde() {
705let duration = TimeDelta::new(123, 456).unwrap();
706assert_eq!(
707 serde_json::from_value::<TimeDelta>(serde_json::to_value(duration).unwrap())
708 .unwrap(),
709 duration
710 );
711 }
712713#[test]
714 #[should_panic(expected = "TimeDelta out of bounds")]
715fn test_serde_oob_panic() {
716let _ =
717 serde_json::from_value::<TimeDelta>(serde_json::json!([MAX.secs + 1, 0])).unwrap();
718 }
719 }
720}
721722#[cfg(test)]
723mod tests {
724use super::OutOfRangeError;
725use super::{MAX, MIN, TimeDelta};
726use crate::expect;
727use core::time::Duration;
728729#[test]
730fn test_duration() {
731let days = |d| TimeDelta::try_days(d).unwrap();
732let seconds = |s| TimeDelta::try_seconds(s).unwrap();
733734assert!(seconds(1) != TimeDelta::zero());
735assert_eq!(seconds(1) + seconds(2), seconds(3));
736assert_eq!(seconds(86_399) + seconds(4), days(1) + seconds(3));
737assert_eq!(days(10) - seconds(1000), seconds(863_000));
738assert_eq!(days(10) - seconds(1_000_000), seconds(-136_000));
739assert_eq!(
740 days(2) + seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
741 days(3) + TimeDelta::nanoseconds(234_567_890)
742 );
743assert_eq!(-days(3), days(-3));
744assert_eq!(-(days(3) + seconds(70)), days(-4) + seconds(86_400 - 70));
745746let mut d = TimeDelta::default();
747 d += TimeDelta::try_minutes(1).unwrap();
748 d -= seconds(30);
749assert_eq!(d, seconds(30));
750 }
751752#[test]
753fn test_duration_num_days() {
754assert_eq!(TimeDelta::zero().num_days(), 0);
755assert_eq!(TimeDelta::try_days(1).unwrap().num_days(), 1);
756assert_eq!(TimeDelta::try_days(-1).unwrap().num_days(), -1);
757assert_eq!(TimeDelta::try_seconds(86_399).unwrap().num_days(), 0);
758assert_eq!(TimeDelta::try_seconds(86_401).unwrap().num_days(), 1);
759assert_eq!(TimeDelta::try_seconds(-86_399).unwrap().num_days(), 0);
760assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().num_days(), -1);
761assert_eq!(TimeDelta::try_days(i32::MAX as i64).unwrap().num_days(), i32::MAX as i64);
762assert_eq!(TimeDelta::try_days(i32::MIN as i64).unwrap().num_days(), i32::MIN as i64);
763 }
764765#[test]
766fn test_duration_num_seconds() {
767assert_eq!(TimeDelta::zero().num_seconds(), 0);
768assert_eq!(TimeDelta::try_seconds(1).unwrap().num_seconds(), 1);
769assert_eq!(TimeDelta::try_seconds(-1).unwrap().num_seconds(), -1);
770assert_eq!(TimeDelta::try_milliseconds(999).unwrap().num_seconds(), 0);
771assert_eq!(TimeDelta::try_milliseconds(1001).unwrap().num_seconds(), 1);
772assert_eq!(TimeDelta::try_milliseconds(-999).unwrap().num_seconds(), 0);
773assert_eq!(TimeDelta::try_milliseconds(-1001).unwrap().num_seconds(), -1);
774 }
775776#[test]
777fn test_duration_seconds_max_allowed() {
778let duration = TimeDelta::try_seconds(i64::MAX / 1_000).unwrap();
779assert_eq!(duration.num_seconds(), i64::MAX / 1_000);
780assert_eq!(
781 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
782 i64::MAX as i128 / 1_000 * 1_000_000_000
783);
784 }
785786#[test]
787fn test_duration_seconds_max_overflow() {
788assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none());
789 }
790791#[test]
792 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
793fn test_duration_seconds_max_overflow_panic() {
794let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
795 }
796797#[test]
798fn test_duration_seconds_min_allowed() {
799let duration = TimeDelta::try_seconds(i64::MIN / 1_000).unwrap(); // Same as -i64::MAX / 1_000 due to rounding
800assert_eq!(duration.num_seconds(), i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding
801assert_eq!(
802 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
803 -i64::MAX as i128 / 1_000 * 1_000_000_000
804);
805 }
806807#[test]
808fn test_duration_seconds_min_underflow() {
809assert!(TimeDelta::try_seconds(-i64::MAX / 1_000 - 1).is_none());
810 }
811812#[test]
813 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
814fn test_duration_seconds_min_underflow_panic() {
815let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1);
816 }
817818#[test]
819fn test_duration_as_seconds_f64() {
820assert_eq!(TimeDelta::seconds(1).as_seconds_f64(), 1.0);
821assert_eq!(TimeDelta::seconds(-1).as_seconds_f64(), -1.0);
822assert_eq!(TimeDelta::seconds(100).as_seconds_f64(), 100.0);
823assert_eq!(TimeDelta::seconds(-100).as_seconds_f64(), -100.0);
824825assert_eq!(TimeDelta::milliseconds(500).as_seconds_f64(), 0.5);
826assert_eq!(TimeDelta::milliseconds(-500).as_seconds_f64(), -0.5);
827assert_eq!(TimeDelta::milliseconds(1_500).as_seconds_f64(), 1.5);
828assert_eq!(TimeDelta::milliseconds(-1_500).as_seconds_f64(), -1.5);
829 }
830831#[test]
832fn test_duration_as_seconds_f32() {
833assert_eq!(TimeDelta::seconds(1).as_seconds_f32(), 1.0);
834assert_eq!(TimeDelta::seconds(-1).as_seconds_f32(), -1.0);
835assert_eq!(TimeDelta::seconds(100).as_seconds_f32(), 100.0);
836assert_eq!(TimeDelta::seconds(-100).as_seconds_f32(), -100.0);
837838assert_eq!(TimeDelta::milliseconds(500).as_seconds_f32(), 0.5);
839assert_eq!(TimeDelta::milliseconds(-500).as_seconds_f32(), -0.5);
840assert_eq!(TimeDelta::milliseconds(1_500).as_seconds_f32(), 1.5);
841assert_eq!(TimeDelta::milliseconds(-1_500).as_seconds_f32(), -1.5);
842 }
843844#[test]
845fn test_duration_subsec_nanos() {
846assert_eq!(TimeDelta::zero().subsec_nanos(), 0);
847assert_eq!(TimeDelta::nanoseconds(1).subsec_nanos(), 1);
848assert_eq!(TimeDelta::nanoseconds(-1).subsec_nanos(), -1);
849assert_eq!(TimeDelta::seconds(1).subsec_nanos(), 0);
850assert_eq!(TimeDelta::nanoseconds(1_000_000_001).subsec_nanos(), 1);
851 }
852853#[test]
854fn test_duration_subsec_micros() {
855assert_eq!(TimeDelta::zero().subsec_micros(), 0);
856assert_eq!(TimeDelta::microseconds(1).subsec_micros(), 1);
857assert_eq!(TimeDelta::microseconds(-1).subsec_micros(), -1);
858assert_eq!(TimeDelta::seconds(1).subsec_micros(), 0);
859assert_eq!(TimeDelta::microseconds(1_000_001).subsec_micros(), 1);
860assert_eq!(TimeDelta::nanoseconds(1_000_001_999).subsec_micros(), 1);
861 }
862863#[test]
864fn test_duration_subsec_millis() {
865assert_eq!(TimeDelta::zero().subsec_millis(), 0);
866assert_eq!(TimeDelta::milliseconds(1).subsec_millis(), 1);
867assert_eq!(TimeDelta::milliseconds(-1).subsec_millis(), -1);
868assert_eq!(TimeDelta::seconds(1).subsec_millis(), 0);
869assert_eq!(TimeDelta::milliseconds(1_001).subsec_millis(), 1);
870assert_eq!(TimeDelta::microseconds(1_001_999).subsec_millis(), 1);
871 }
872873#[test]
874fn test_duration_num_milliseconds() {
875assert_eq!(TimeDelta::zero().num_milliseconds(), 0);
876assert_eq!(TimeDelta::try_milliseconds(1).unwrap().num_milliseconds(), 1);
877assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().num_milliseconds(), -1);
878assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0);
879assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1);
880assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0);
881assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1);
882 }
883884#[test]
885fn test_duration_milliseconds_max_allowed() {
886// The maximum number of milliseconds acceptable through the constructor is
887 // equal to the number that can be stored in a TimeDelta.
888let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
889assert_eq!(duration.num_milliseconds(), i64::MAX);
890assert_eq!(
891 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
892 i64::MAX as i128 * 1_000_000
893);
894 }
895896#[test]
897fn test_duration_milliseconds_max_overflow() {
898// Here we ensure that trying to add one millisecond to the maximum storable
899 // value will fail.
900assert!(
901 TimeDelta::try_milliseconds(i64::MAX)
902 .unwrap()
903 .checked_add(&TimeDelta::try_milliseconds(1).unwrap())
904 .is_none()
905 );
906 }
907908#[test]
909fn test_duration_milliseconds_min_allowed() {
910// The minimum number of milliseconds acceptable through the constructor is
911 // not equal to the number that can be stored in a TimeDelta - there is a
912 // difference of one (i64::MIN vs -i64::MAX).
913let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
914assert_eq!(duration.num_milliseconds(), -i64::MAX);
915assert_eq!(
916 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
917 -i64::MAX as i128 * 1_000_000
918);
919 }
920921#[test]
922fn test_duration_milliseconds_min_underflow() {
923// Here we ensure that trying to subtract one millisecond from the minimum
924 // storable value will fail.
925assert!(
926 TimeDelta::try_milliseconds(-i64::MAX)
927 .unwrap()
928 .checked_sub(&TimeDelta::try_milliseconds(1).unwrap())
929 .is_none()
930 );
931 }
932933#[test]
934 #[should_panic(expected = "TimeDelta::milliseconds out of bounds")]
935fn test_duration_milliseconds_min_underflow_panic() {
936// Here we ensure that trying to create a value one millisecond below the
937 // minimum storable value will fail. This test is necessary because the
938 // storable range is -i64::MAX, but the constructor type of i64 will allow
939 // i64::MIN, which is one value below.
940let _ = TimeDelta::milliseconds(i64::MIN); // Same as -i64::MAX - 1
941}
942943#[test]
944fn test_duration_num_microseconds() {
945assert_eq!(TimeDelta::zero().num_microseconds(), Some(0));
946assert_eq!(TimeDelta::microseconds(1).num_microseconds(), Some(1));
947assert_eq!(TimeDelta::microseconds(-1).num_microseconds(), Some(-1));
948assert_eq!(TimeDelta::nanoseconds(999).num_microseconds(), Some(0));
949assert_eq!(TimeDelta::nanoseconds(1001).num_microseconds(), Some(1));
950assert_eq!(TimeDelta::nanoseconds(-999).num_microseconds(), Some(0));
951assert_eq!(TimeDelta::nanoseconds(-1001).num_microseconds(), Some(-1));
952953// overflow checks
954const MICROS_PER_DAY: i64 = 86_400_000_000;
955assert_eq!(
956 TimeDelta::try_days(i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
957Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
958 );
959assert_eq!(
960 TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY).unwrap().num_microseconds(),
961Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
962 );
963assert_eq!(
964 TimeDelta::try_days(i64::MAX / MICROS_PER_DAY + 1).unwrap().num_microseconds(),
965None
966);
967assert_eq!(
968 TimeDelta::try_days(-i64::MAX / MICROS_PER_DAY - 1).unwrap().num_microseconds(),
969None
970);
971 }
972#[test]
973fn test_duration_microseconds_max_allowed() {
974// The number of microseconds acceptable through the constructor is far
975 // fewer than the number that can actually be stored in a TimeDelta, so this
976 // is not a particular insightful test.
977let duration = TimeDelta::microseconds(i64::MAX);
978assert_eq!(duration.num_microseconds(), Some(i64::MAX));
979assert_eq!(
980 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
981 i64::MAX as i128 * 1_000
982);
983// Here we create a TimeDelta with the maximum possible number of
984 // microseconds by creating a TimeDelta with the maximum number of
985 // milliseconds and then checking that the number of microseconds matches
986 // the storage limit.
987let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
988assert!(duration.num_microseconds().is_none());
989assert_eq!(
990 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
991 i64::MAX as i128 * 1_000_000
992);
993 }
994#[test]
995fn test_duration_microseconds_max_overflow() {
996// This test establishes that a TimeDelta can store more microseconds than
997 // are representable through the return of duration.num_microseconds().
998let duration = TimeDelta::microseconds(i64::MAX) + TimeDelta::microseconds(1);
999assert!(duration.num_microseconds().is_none());
1000assert_eq!(
1001 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1002 (i64::MAX as i128 + 1) * 1_000
1003);
1004// Here we ensure that trying to add one microsecond to the maximum storable
1005 // value will fail.
1006assert!(
1007 TimeDelta::try_milliseconds(i64::MAX)
1008 .unwrap()
1009 .checked_add(&TimeDelta::microseconds(1))
1010 .is_none()
1011 );
1012 }
1013#[test]
1014fn test_duration_microseconds_min_allowed() {
1015// The number of microseconds acceptable through the constructor is far
1016 // fewer than the number that can actually be stored in a TimeDelta, so this
1017 // is not a particular insightful test.
1018let duration = TimeDelta::microseconds(i64::MIN);
1019assert_eq!(duration.num_microseconds(), Some(i64::MIN));
1020assert_eq!(
1021 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1022 i64::MIN as i128 * 1_000
1023);
1024// Here we create a TimeDelta with the minimum possible number of
1025 // microseconds by creating a TimeDelta with the minimum number of
1026 // milliseconds and then checking that the number of microseconds matches
1027 // the storage limit.
1028let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
1029assert!(duration.num_microseconds().is_none());
1030assert_eq!(
1031 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1032 -i64::MAX as i128 * 1_000_000
1033);
1034 }
1035#[test]
1036fn test_duration_microseconds_min_underflow() {
1037// This test establishes that a TimeDelta can store more microseconds than
1038 // are representable through the return of duration.num_microseconds().
1039let duration = TimeDelta::microseconds(i64::MIN) - TimeDelta::microseconds(1);
1040assert!(duration.num_microseconds().is_none());
1041assert_eq!(
1042 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1043 (i64::MIN as i128 - 1) * 1_000
1044);
1045// Here we ensure that trying to subtract one microsecond from the minimum
1046 // storable value will fail.
1047assert!(
1048 TimeDelta::try_milliseconds(-i64::MAX)
1049 .unwrap()
1050 .checked_sub(&TimeDelta::microseconds(1))
1051 .is_none()
1052 );
1053 }
10541055#[test]
1056fn test_duration_num_nanoseconds() {
1057assert_eq!(TimeDelta::zero().num_nanoseconds(), Some(0));
1058assert_eq!(TimeDelta::nanoseconds(1).num_nanoseconds(), Some(1));
1059assert_eq!(TimeDelta::nanoseconds(-1).num_nanoseconds(), Some(-1));
10601061// overflow checks
1062const NANOS_PER_DAY: i64 = 86_400_000_000_000;
1063assert_eq!(
1064 TimeDelta::try_days(i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
1065Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
1066 );
1067assert_eq!(
1068 TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY).unwrap().num_nanoseconds(),
1069Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
1070 );
1071assert_eq!(
1072 TimeDelta::try_days(i64::MAX / NANOS_PER_DAY + 1).unwrap().num_nanoseconds(),
1073None
1074);
1075assert_eq!(
1076 TimeDelta::try_days(-i64::MAX / NANOS_PER_DAY - 1).unwrap().num_nanoseconds(),
1077None
1078);
1079 }
1080#[test]
1081fn test_duration_nanoseconds_max_allowed() {
1082// The number of nanoseconds acceptable through the constructor is far fewer
1083 // than the number that can actually be stored in a TimeDelta, so this is not
1084 // a particular insightful test.
1085let duration = TimeDelta::nanoseconds(i64::MAX);
1086assert_eq!(duration.num_nanoseconds(), Some(i64::MAX));
1087assert_eq!(
1088 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1089 i64::MAX as i128
1090 );
1091// Here we create a TimeDelta with the maximum possible number of nanoseconds
1092 // by creating a TimeDelta with the maximum number of milliseconds and then
1093 // checking that the number of nanoseconds matches the storage limit.
1094let duration = TimeDelta::try_milliseconds(i64::MAX).unwrap();
1095assert!(duration.num_nanoseconds().is_none());
1096assert_eq!(
1097 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1098 i64::MAX as i128 * 1_000_000
1099);
1100 }
11011102#[test]
1103fn test_duration_nanoseconds_max_overflow() {
1104// This test establishes that a TimeDelta can store more nanoseconds than are
1105 // representable through the return of duration.num_nanoseconds().
1106let duration = TimeDelta::nanoseconds(i64::MAX) + TimeDelta::nanoseconds(1);
1107assert!(duration.num_nanoseconds().is_none());
1108assert_eq!(
1109 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1110 i64::MAX as i128 + 1
1111);
1112// Here we ensure that trying to add one nanosecond to the maximum storable
1113 // value will fail.
1114assert!(
1115 TimeDelta::try_milliseconds(i64::MAX)
1116 .unwrap()
1117 .checked_add(&TimeDelta::nanoseconds(1))
1118 .is_none()
1119 );
1120 }
11211122#[test]
1123fn test_duration_nanoseconds_min_allowed() {
1124// The number of nanoseconds acceptable through the constructor is far fewer
1125 // than the number that can actually be stored in a TimeDelta, so this is not
1126 // a particular insightful test.
1127let duration = TimeDelta::nanoseconds(i64::MIN);
1128assert_eq!(duration.num_nanoseconds(), Some(i64::MIN));
1129assert_eq!(
1130 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1131 i64::MIN as i128
1132 );
1133// Here we create a TimeDelta with the minimum possible number of nanoseconds
1134 // by creating a TimeDelta with the minimum number of milliseconds and then
1135 // checking that the number of nanoseconds matches the storage limit.
1136let duration = TimeDelta::try_milliseconds(-i64::MAX).unwrap();
1137assert!(duration.num_nanoseconds().is_none());
1138assert_eq!(
1139 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1140 -i64::MAX as i128 * 1_000_000
1141);
1142 }
11431144#[test]
1145fn test_duration_nanoseconds_min_underflow() {
1146// This test establishes that a TimeDelta can store more nanoseconds than are
1147 // representable through the return of duration.num_nanoseconds().
1148let duration = TimeDelta::nanoseconds(i64::MIN) - TimeDelta::nanoseconds(1);
1149assert!(duration.num_nanoseconds().is_none());
1150assert_eq!(
1151 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
1152 i64::MIN as i128 - 1
1153);
1154// Here we ensure that trying to subtract one nanosecond from the minimum
1155 // storable value will fail.
1156assert!(
1157 TimeDelta::try_milliseconds(-i64::MAX)
1158 .unwrap()
1159 .checked_sub(&TimeDelta::nanoseconds(1))
1160 .is_none()
1161 );
1162 }
11631164#[test]
1165fn test_max() {
1166assert_eq!(
1167 MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128,
1168 i64::MAX as i128 * 1_000_000
1169);
1170assert_eq!(MAX, TimeDelta::try_milliseconds(i64::MAX).unwrap());
1171assert_eq!(MAX.num_milliseconds(), i64::MAX);
1172assert_eq!(MAX.num_microseconds(), None);
1173assert_eq!(MAX.num_nanoseconds(), None);
1174 }
11751176#[test]
1177fn test_min() {
1178assert_eq!(
1179 MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128,
1180 -i64::MAX as i128 * 1_000_000
1181);
1182assert_eq!(MIN, TimeDelta::try_milliseconds(-i64::MAX).unwrap());
1183assert_eq!(MIN.num_milliseconds(), -i64::MAX);
1184assert_eq!(MIN.num_microseconds(), None);
1185assert_eq!(MIN.num_nanoseconds(), None);
1186 }
11871188#[test]
1189fn test_duration_ord() {
1190let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
11911192assert!(milliseconds(1) < milliseconds(2));
1193assert!(milliseconds(2) > milliseconds(1));
1194assert!(milliseconds(-1) > milliseconds(-2));
1195assert!(milliseconds(-2) < milliseconds(-1));
1196assert!(milliseconds(-1) < milliseconds(1));
1197assert!(milliseconds(1) > milliseconds(-1));
1198assert!(milliseconds(0) < milliseconds(1));
1199assert!(milliseconds(0) > milliseconds(-1));
1200assert!(milliseconds(1_001) < milliseconds(1_002));
1201assert!(milliseconds(-1_001) > milliseconds(-1_002));
1202assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891));
1203assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891));
1204assert!(milliseconds(i64::MAX) > milliseconds(i64::MAX - 1));
1205assert!(milliseconds(-i64::MAX) < milliseconds(-i64::MAX + 1));
1206 }
12071208#[test]
1209fn test_duration_checked_ops() {
1210let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
1211let seconds = |s| TimeDelta::try_seconds(s).unwrap();
12121213assert_eq!(
1214 milliseconds(i64::MAX).checked_add(&milliseconds(0)),
1215Some(milliseconds(i64::MAX))
1216 );
1217assert_eq!(
1218 milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
1219Some(milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
1220 );
1221assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::microseconds(1000)).is_none());
1222assert!(milliseconds(i64::MAX).checked_add(&TimeDelta::nanoseconds(1)).is_none());
12231224assert_eq!(
1225 milliseconds(-i64::MAX).checked_sub(&milliseconds(0)),
1226Some(milliseconds(-i64::MAX))
1227 );
1228assert_eq!(
1229 milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
1230Some(milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
1231 );
1232assert!(milliseconds(-i64::MAX).checked_sub(&milliseconds(1)).is_none());
1233assert!(milliseconds(-i64::MAX).checked_sub(&TimeDelta::nanoseconds(1)).is_none());
12341235assert!(seconds(i64::MAX / 1000).checked_mul(2000).is_none());
1236assert!(seconds(i64::MIN / 1000).checked_mul(2000).is_none());
1237assert!(seconds(1).checked_div(0).is_none());
1238 }
12391240#[test]
1241fn test_duration_abs() {
1242let milliseconds = |ms| TimeDelta::try_milliseconds(ms).unwrap();
12431244assert_eq!(milliseconds(1300).abs(), milliseconds(1300));
1245assert_eq!(milliseconds(1000).abs(), milliseconds(1000));
1246assert_eq!(milliseconds(300).abs(), milliseconds(300));
1247assert_eq!(milliseconds(0).abs(), milliseconds(0));
1248assert_eq!(milliseconds(-300).abs(), milliseconds(300));
1249assert_eq!(milliseconds(-700).abs(), milliseconds(700));
1250assert_eq!(milliseconds(-1000).abs(), milliseconds(1000));
1251assert_eq!(milliseconds(-1300).abs(), milliseconds(1300));
1252assert_eq!(milliseconds(-1700).abs(), milliseconds(1700));
1253assert_eq!(milliseconds(-i64::MAX).abs(), milliseconds(i64::MAX));
1254 }
12551256#[test]
1257 #[allow(clippy::erasing_op)]
1258fn test_duration_mul() {
1259assert_eq!(TimeDelta::zero() * i32::MAX, TimeDelta::zero());
1260assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero());
1261assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero());
1262assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1));
1263assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::try_seconds(1).unwrap());
1264assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1265assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::try_seconds(1).unwrap());
1266assert_eq!(
1267 TimeDelta::nanoseconds(30) * 333_333_333,
1268 TimeDelta::try_seconds(10).unwrap() - TimeDelta::nanoseconds(10)
1269 );
1270assert_eq!(
1271 (TimeDelta::nanoseconds(1)
1272 + TimeDelta::try_seconds(1).unwrap()
1273 + TimeDelta::try_days(1).unwrap())
1274 * 3,
1275 TimeDelta::nanoseconds(3)
1276 + TimeDelta::try_seconds(3).unwrap()
1277 + TimeDelta::try_days(3).unwrap()
1278 );
1279assert_eq!(
1280 TimeDelta::try_milliseconds(1500).unwrap() * -2,
1281 TimeDelta::try_seconds(-3).unwrap()
1282 );
1283assert_eq!(
1284 TimeDelta::try_milliseconds(-1500).unwrap() * 2,
1285 TimeDelta::try_seconds(-3).unwrap()
1286 );
1287 }
12881289#[test]
1290fn test_duration_div() {
1291assert_eq!(TimeDelta::zero() / i32::MAX, TimeDelta::zero());
1292assert_eq!(TimeDelta::zero() / i32::MIN, TimeDelta::zero());
1293assert_eq!(TimeDelta::nanoseconds(123_456_789) / 1, TimeDelta::nanoseconds(123_456_789));
1294assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789));
1295assert_eq!(-TimeDelta::nanoseconds(123_456_789) / -1, TimeDelta::nanoseconds(123_456_789));
1296assert_eq!(-TimeDelta::nanoseconds(123_456_789) / 1, -TimeDelta::nanoseconds(123_456_789));
1297assert_eq!(TimeDelta::try_seconds(1).unwrap() / 3, TimeDelta::nanoseconds(333_333_333));
1298assert_eq!(TimeDelta::try_seconds(4).unwrap() / 3, TimeDelta::nanoseconds(1_333_333_333));
1299assert_eq!(
1300 TimeDelta::try_seconds(-1).unwrap() / 2,
1301 TimeDelta::try_milliseconds(-500).unwrap()
1302 );
1303assert_eq!(
1304 TimeDelta::try_seconds(1).unwrap() / -2,
1305 TimeDelta::try_milliseconds(-500).unwrap()
1306 );
1307assert_eq!(
1308 TimeDelta::try_seconds(-1).unwrap() / -2,
1309 TimeDelta::try_milliseconds(500).unwrap()
1310 );
1311assert_eq!(TimeDelta::try_seconds(-4).unwrap() / 3, TimeDelta::nanoseconds(-1_333_333_333));
1312assert_eq!(TimeDelta::try_seconds(-4).unwrap() / -3, TimeDelta::nanoseconds(1_333_333_333));
1313 }
13141315#[test]
1316fn test_duration_sum() {
1317let duration_list_1 = [TimeDelta::zero(), TimeDelta::try_seconds(1).unwrap()];
1318let sum_1: TimeDelta = duration_list_1.iter().sum();
1319assert_eq!(sum_1, TimeDelta::try_seconds(1).unwrap());
13201321let duration_list_2 = [
1322 TimeDelta::zero(),
1323 TimeDelta::try_seconds(1).unwrap(),
1324 TimeDelta::try_seconds(6).unwrap(),
1325 TimeDelta::try_seconds(10).unwrap(),
1326 ];
1327let sum_2: TimeDelta = duration_list_2.iter().sum();
1328assert_eq!(sum_2, TimeDelta::try_seconds(17).unwrap());
13291330let duration_arr = [
1331 TimeDelta::zero(),
1332 TimeDelta::try_seconds(1).unwrap(),
1333 TimeDelta::try_seconds(6).unwrap(),
1334 TimeDelta::try_seconds(10).unwrap(),
1335 ];
1336let sum_3: TimeDelta = duration_arr.into_iter().sum();
1337assert_eq!(sum_3, TimeDelta::try_seconds(17).unwrap());
1338 }
13391340#[test]
1341fn test_duration_fmt() {
1342assert_eq!(TimeDelta::zero().to_string(), "P0D");
1343assert_eq!(TimeDelta::try_days(42).unwrap().to_string(), "PT3628800S");
1344assert_eq!(TimeDelta::try_days(-42).unwrap().to_string(), "-PT3628800S");
1345assert_eq!(TimeDelta::try_seconds(42).unwrap().to_string(), "PT42S");
1346assert_eq!(TimeDelta::try_milliseconds(42).unwrap().to_string(), "PT0.042S");
1347assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S");
1348assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S");
1349assert_eq!(
1350 (TimeDelta::try_days(7).unwrap() + TimeDelta::try_milliseconds(6543).unwrap())
1351 .to_string(),
1352"PT604806.543S"
1353);
1354assert_eq!(TimeDelta::try_seconds(-86_401).unwrap().to_string(), "-PT86401S");
1355assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S");
13561357// the format specifier should have no effect on `TimeDelta`
1358assert_eq!(
1359format!(
1360"{:30}",
1361 TimeDelta::try_days(1).unwrap() + TimeDelta::try_milliseconds(2345).unwrap()
1362 ),
1363"PT86402.345S"
1364);
1365 }
13661367#[test]
1368fn test_to_std() {
1369assert_eq!(TimeDelta::try_seconds(1).unwrap().to_std(), Ok(Duration::new(1, 0)));
1370assert_eq!(TimeDelta::try_seconds(86_401).unwrap().to_std(), Ok(Duration::new(86_401, 0)));
1371assert_eq!(
1372 TimeDelta::try_milliseconds(123).unwrap().to_std(),
1373Ok(Duration::new(0, 123_000_000))
1374 );
1375assert_eq!(
1376 TimeDelta::try_milliseconds(123_765).unwrap().to_std(),
1377Ok(Duration::new(123, 765_000_000))
1378 );
1379assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777)));
1380assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000)));
1381assert_eq!(TimeDelta::try_seconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1382assert_eq!(TimeDelta::try_milliseconds(-1).unwrap().to_std(), Err(OutOfRangeError(())));
1383 }
13841385#[test]
1386fn test_from_std() {
1387assert_eq!(
1388Ok(TimeDelta::try_seconds(1).unwrap()),
1389 TimeDelta::from_std(Duration::new(1, 0))
1390 );
1391assert_eq!(
1392Ok(TimeDelta::try_seconds(86_401).unwrap()),
1393 TimeDelta::from_std(Duration::new(86_401, 0))
1394 );
1395assert_eq!(
1396Ok(TimeDelta::try_milliseconds(123).unwrap()),
1397 TimeDelta::from_std(Duration::new(0, 123_000_000))
1398 );
1399assert_eq!(
1400Ok(TimeDelta::try_milliseconds(123_765).unwrap()),
1401 TimeDelta::from_std(Duration::new(123, 765_000_000))
1402 );
1403assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777)));
1404assert_eq!(Ok(MAX), TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_000)));
1405assert_eq!(
1406 TimeDelta::from_std(Duration::new(9_223_372_036_854_776, 0)),
1407Err(OutOfRangeError(()))
1408 );
1409assert_eq!(
1410 TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_001)),
1411Err(OutOfRangeError(()))
1412 );
1413 }
14141415#[test]
1416fn test_duration_const() {
1417const ONE_WEEK: TimeDelta = expect(TimeDelta::try_weeks(1), "");
1418const ONE_DAY: TimeDelta = expect(TimeDelta::try_days(1), "");
1419const ONE_HOUR: TimeDelta = expect(TimeDelta::try_hours(1), "");
1420const ONE_MINUTE: TimeDelta = expect(TimeDelta::try_minutes(1), "");
1421const ONE_SECOND: TimeDelta = expect(TimeDelta::try_seconds(1), "");
1422const ONE_MILLI: TimeDelta = expect(TimeDelta::try_milliseconds(1), "");
1423const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1);
1424const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1);
1425let combo: TimeDelta = ONE_WEEK
1426 + ONE_DAY
1427 + ONE_HOUR
1428 + ONE_MINUTE
1429 + ONE_SECOND
1430 + ONE_MILLI
1431 + ONE_MICRO
1432 + ONE_NANO;
14331434assert!(ONE_WEEK != TimeDelta::zero());
1435assert!(ONE_DAY != TimeDelta::zero());
1436assert!(ONE_HOUR != TimeDelta::zero());
1437assert!(ONE_MINUTE != TimeDelta::zero());
1438assert!(ONE_SECOND != TimeDelta::zero());
1439assert!(ONE_MILLI != TimeDelta::zero());
1440assert!(ONE_MICRO != TimeDelta::zero());
1441assert!(ONE_NANO != TimeDelta::zero());
1442assert_eq!(
1443 combo,
1444 TimeDelta::try_seconds(86400 * 7 + 86400 + 3600 + 60 + 1).unwrap()
1445 + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000)
1446 );
1447 }
14481449#[test]
1450 #[cfg(feature = "rkyv-validation")]
1451fn test_rkyv_validation() {
1452let duration = TimeDelta::try_seconds(1).unwrap();
1453let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
1454assert_eq!(rkyv::from_bytes::<TimeDelta>(&bytes).unwrap(), duration);
1455 }
1456}