1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Temporal quantification
12
13 use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
14 use core::time::Duration;
15 use core::{fmt, i64};
16 #[cfg(feature = "std")]
17 use std::error::Error;
18
19 use crate::{expect, try_opt};
20
21 #[cfg(any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"))]
22 use rkyv::{Archive, Deserialize, Serialize};
23
24 /// The number of nanoseconds in a microsecond.
25 const NANOS_PER_MICRO: i32 = 1000;
26 /// The number of nanoseconds in a millisecond.
27 const NANOS_PER_MILLI: i32 = 1_000_000;
28 /// The number of nanoseconds in seconds.
29 pub(crate) const NANOS_PER_SEC: i32 = 1_000_000_000;
30 /// The number of microseconds per second.
31 const MICROS_PER_SEC: i64 = 1_000_000;
32 /// The number of milliseconds per second.
33 const MILLIS_PER_SEC: i64 = 1000;
34 /// The number of seconds in a minute.
35 const SECS_PER_MINUTE: i64 = 60;
36 /// The number of seconds in an hour.
37 const SECS_PER_HOUR: i64 = 3600;
38 /// The number of (non-leap) seconds in days.
39 const SECS_PER_DAY: i64 = 86_400;
40 /// The number of (non-leap) seconds in a week.
41 const SECS_PER_WEEK: i64 = 604_800;
42
43 /// Time duration with nanosecond precision.
44 ///
45 /// This also allows for negative durations; see individual methods for details.
46 ///
47 /// A `TimeDelta` is represented internally as a complement of seconds and
48 /// nanoseconds. The range is restricted to that of `i64` milliseconds, with the
49 /// minimum value notably being set to `-i64::MAX` rather than allowing the full
50 /// range of `i64::MIN`. This is to allow easy flipping of sign, so that for
51 /// instance `abs()` can be called without any checks.
52 #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
53 #[cfg_attr(
54 any(feature = "rkyv", feature = "rkyv-16", feature = "rkyv-32", feature = "rkyv-64"),
55 derive(Archive, Deserialize, Serialize),
56 archive(compare(PartialEq, PartialOrd)),
57 archive_attr(derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash))
58 )]
59 #[cfg_attr(feature = "rkyv-validation", archive(check_bytes))]
60 pub struct TimeDelta {
61 secs: i64,
62 nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
63 }
64
65 /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
66 pub(crate) const MIN: TimeDelta = TimeDelta {
67 secs: -i64::MAX / MILLIS_PER_SEC - 1,
68 nanos: NANOS_PER_SEC + (-i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
69 };
70
71 /// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
72 pub(crate) const MAX: TimeDelta = TimeDelta {
73 secs: i64::MAX / MILLIS_PER_SEC,
74 nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI,
75 };
76
77 impl TimeDelta {
78 /// Makes a new `TimeDelta` with given number of seconds and nanoseconds.
79 ///
80 /// # Errors
81 ///
82 /// Returns `None` when the duration is out of bounds, or if `nanos` ≥ 1,000,000,000.
new(secs: i64, nanos: u32) -> Option<TimeDelta>83 pub const fn new(secs: i64, nanos: u32) -> Option<TimeDelta> {
84 if secs < MIN.secs
85 || secs > MAX.secs
86 || nanos >= 1_000_000_000
87 || (secs == MAX.secs && nanos > MAX.nanos as u32)
88 || (secs == MIN.secs && nanos < MIN.nanos as u32)
89 {
90 return None;
91 }
92 Some(TimeDelta { secs, nanos: nanos as i32 })
93 }
94
95 /// Makes a new `TimeDelta` with the given number of weeks.
96 ///
97 /// Equivalent to `TimeDelta::seconds(weeks * 7 * 24 * 60 * 60)` with
98 /// overflow checks.
99 ///
100 /// # Panics
101 ///
102 /// Panics when the duration is out of bounds.
103 #[inline]
104 #[must_use]
weeks(weeks: i64) -> TimeDelta105 pub const fn weeks(weeks: i64) -> TimeDelta {
106 expect!(TimeDelta::try_weeks(weeks), "TimeDelta::weeks out of bounds")
107 }
108
109 /// Makes a new `TimeDelta` with the given number of weeks.
110 ///
111 /// Equivalent to `TimeDelta::seconds(weeks * 7 * 24 * 60 * 60)` with
112 /// overflow checks.
113 ///
114 /// # Errors
115 ///
116 /// Returns `None` when the `TimeDelta` would be out of bounds.
117 #[inline]
try_weeks(weeks: i64) -> Option<TimeDelta>118 pub const fn try_weeks(weeks: i64) -> Option<TimeDelta> {
119 TimeDelta::try_seconds(try_opt!(weeks.checked_mul(SECS_PER_WEEK)))
120 }
121
122 /// Makes a new `TimeDelta` with the given number of days.
123 ///
124 /// Equivalent to `TimeDelta::seconds(days * 24 * 60 * 60)` with overflow
125 /// checks.
126 ///
127 /// # Panics
128 ///
129 /// Panics when the `TimeDelta` would be out of bounds.
130 #[inline]
131 #[must_use]
days(days: i64) -> TimeDelta132 pub const fn days(days: i64) -> TimeDelta {
133 expect!(TimeDelta::try_days(days), "TimeDelta::days out of bounds")
134 }
135
136 /// Makes a new `TimeDelta` with the given number of days.
137 ///
138 /// Equivalent to `TimeDelta::seconds(days * 24 * 60 * 60)` with overflow
139 /// checks.
140 ///
141 /// # Errors
142 ///
143 /// Returns `None` when the `TimeDelta` would be out of bounds.
144 #[inline]
try_days(days: i64) -> Option<TimeDelta>145 pub const fn try_days(days: i64) -> Option<TimeDelta> {
146 TimeDelta::try_seconds(try_opt!(days.checked_mul(SECS_PER_DAY)))
147 }
148
149 /// Makes a new `TimeDelta` with the given number of hours.
150 ///
151 /// Equivalent to `TimeDelta::seconds(hours * 60 * 60)` with overflow checks.
152 ///
153 /// # Panics
154 ///
155 /// Panics when the `TimeDelta` would be out of bounds.
156 #[inline]
157 #[must_use]
hours(hours: i64) -> TimeDelta158 pub const fn hours(hours: i64) -> TimeDelta {
159 expect!(TimeDelta::try_hours(hours), "TimeDelta::hours out of bounds")
160 }
161
162 /// Makes a new `TimeDelta` with the given number of hours.
163 ///
164 /// Equivalent to `TimeDelta::seconds(hours * 60 * 60)` with overflow checks.
165 ///
166 /// # Errors
167 ///
168 /// Returns `None` when the `TimeDelta` would be out of bounds.
169 #[inline]
try_hours(hours: i64) -> Option<TimeDelta>170 pub const fn try_hours(hours: i64) -> Option<TimeDelta> {
171 TimeDelta::try_seconds(try_opt!(hours.checked_mul(SECS_PER_HOUR)))
172 }
173
174 /// Makes a new `TimeDelta` with the given number of minutes.
175 ///
176 /// Equivalent to `TimeDelta::seconds(minutes * 60)` with overflow checks.
177 ///
178 /// # Panics
179 ///
180 /// Panics when the `TimeDelta` would be out of bounds.
181 #[inline]
182 #[must_use]
minutes(minutes: i64) -> TimeDelta183 pub const fn minutes(minutes: i64) -> TimeDelta {
184 expect!(TimeDelta::try_minutes(minutes), "TimeDelta::minutes out of bounds")
185 }
186
187 /// Makes a new `TimeDelta` with the given number of minutes.
188 ///
189 /// Equivalent to `TimeDelta::seconds(minutes * 60)` with overflow checks.
190 ///
191 /// # Errors
192 ///
193 /// Returns `None` when the `TimeDelta` would be out of bounds.
194 #[inline]
try_minutes(minutes: i64) -> Option<TimeDelta>195 pub const fn try_minutes(minutes: i64) -> Option<TimeDelta> {
196 TimeDelta::try_seconds(try_opt!(minutes.checked_mul(SECS_PER_MINUTE)))
197 }
198
199 /// Makes a new `TimeDelta` with the given number of seconds.
200 ///
201 /// # Panics
202 ///
203 /// Panics when `seconds` is more than `i64::MAX / 1_000` or less than `-i64::MAX / 1_000`
204 /// (in this context, this is the same as `i64::MIN / 1_000` due to rounding).
205 #[inline]
206 #[must_use]
seconds(seconds: i64) -> TimeDelta207 pub const fn seconds(seconds: i64) -> TimeDelta {
208 expect!(TimeDelta::try_seconds(seconds), "TimeDelta::seconds out of bounds")
209 }
210
211 /// Makes a new `TimeDelta` with the given number of seconds.
212 ///
213 /// # Errors
214 ///
215 /// Returns `None` when `seconds` is more than `i64::MAX / 1_000` or less than
216 /// `-i64::MAX / 1_000` (in this context, this is the same as `i64::MIN / 1_000` due to
217 /// rounding).
218 #[inline]
try_seconds(seconds: i64) -> Option<TimeDelta>219 pub const fn try_seconds(seconds: i64) -> Option<TimeDelta> {
220 TimeDelta::new(seconds, 0)
221 }
222
223 /// Makes a new `TimeDelta` with the given number of milliseconds.
224 ///
225 /// # Panics
226 ///
227 /// Panics when the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more than
228 /// `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
229 #[inline]
milliseconds(milliseconds: i64) -> TimeDelta230 pub const fn milliseconds(milliseconds: i64) -> TimeDelta {
231 expect!(TimeDelta::try_milliseconds(milliseconds), "TimeDelta::milliseconds out of bounds")
232 }
233
234 /// Makes a new `TimeDelta` with the given number of milliseconds.
235 ///
236 /// # Errors
237 ///
238 /// Returns `None` the `TimeDelta` would be out of bounds, i.e. when `milliseconds` is more
239 /// than `i64::MAX` or less than `-i64::MAX`. Notably, this is not the same as `i64::MIN`.
240 #[inline]
try_milliseconds(milliseconds: i64) -> Option<TimeDelta>241 pub const fn try_milliseconds(milliseconds: i64) -> Option<TimeDelta> {
242 // We don't need to compare against MAX, as this function accepts an
243 // i64, and MAX is aligned to i64::MAX milliseconds.
244 if milliseconds < -i64::MAX {
245 return None;
246 }
247 let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
248 let d = TimeDelta { secs, nanos: millis as i32 * NANOS_PER_MILLI };
249 Some(d)
250 }
251
252 /// Makes a new `TimeDelta` with the given number of microseconds.
253 ///
254 /// The number of microseconds acceptable by this constructor is less than
255 /// the total number that can actually be stored in a `TimeDelta`, so it is
256 /// not possible to specify a value that would be out of bounds. This
257 /// function is therefore infallible.
258 #[inline]
microseconds(microseconds: i64) -> TimeDelta259 pub const fn microseconds(microseconds: i64) -> TimeDelta {
260 let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
261 let nanos = micros as i32 * NANOS_PER_MICRO;
262 TimeDelta { secs, nanos }
263 }
264
265 /// Makes a new `TimeDelta` with the given number of nanoseconds.
266 ///
267 /// The number of nanoseconds acceptable by this constructor is less than
268 /// the total number that can actually be stored in a `TimeDelta`, so it is
269 /// not possible to specify a value that would be out of bounds. This
270 /// function is therefore infallible.
271 #[inline]
nanoseconds(nanos: i64) -> TimeDelta272 pub const fn nanoseconds(nanos: i64) -> TimeDelta {
273 let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64);
274 TimeDelta { secs, nanos: nanos as i32 }
275 }
276
277 /// Returns the total number of whole weeks in the `TimeDelta`.
278 #[inline]
num_weeks(&self) -> i64279 pub const fn num_weeks(&self) -> i64 {
280 self.num_days() / 7
281 }
282
283 /// Returns the total number of whole days in the `TimeDelta`.
num_days(&self) -> i64284 pub const fn num_days(&self) -> i64 {
285 self.num_seconds() / SECS_PER_DAY
286 }
287
288 /// Returns the total number of whole hours in the `TimeDelta`.
289 #[inline]
num_hours(&self) -> i64290 pub const fn num_hours(&self) -> i64 {
291 self.num_seconds() / SECS_PER_HOUR
292 }
293
294 /// Returns the total number of whole minutes in the `TimeDelta`.
295 #[inline]
num_minutes(&self) -> i64296 pub const fn num_minutes(&self) -> i64 {
297 self.num_seconds() / SECS_PER_MINUTE
298 }
299
300 /// Returns the total number of whole seconds in the `TimeDelta`.
num_seconds(&self) -> i64301 pub const fn num_seconds(&self) -> i64 {
302 // If secs is negative, nanos should be subtracted from the duration.
303 if self.secs < 0 && self.nanos > 0 {
304 self.secs + 1
305 } else {
306 self.secs
307 }
308 }
309
310 /// Returns the number of nanoseconds such that
311 /// `subsec_nanos() + num_seconds() * NANOS_PER_SEC` is the total number of
312 /// nanoseconds in the `TimeDelta`.
subsec_nanos(&self) -> i32313 pub const fn subsec_nanos(&self) -> i32 {
314 if self.secs < 0 && self.nanos > 0 {
315 self.nanos - NANOS_PER_SEC
316 } else {
317 self.nanos
318 }
319 }
320
321 /// Returns the total number of whole milliseconds in the `TimeDelta`.
num_milliseconds(&self) -> i64322 pub const fn num_milliseconds(&self) -> i64 {
323 // A proper TimeDelta will not overflow, because MIN and MAX are defined such
324 // that the range is within the bounds of an i64, from -i64::MAX through to
325 // +i64::MAX inclusive. Notably, i64::MIN is excluded from this range.
326 let secs_part = self.num_seconds() * MILLIS_PER_SEC;
327 let nanos_part = self.subsec_nanos() / NANOS_PER_MILLI;
328 secs_part + nanos_part as i64
329 }
330
331 /// Returns the total number of whole microseconds in the `TimeDelta`,
332 /// or `None` on overflow (exceeding 2^63 microseconds in either direction).
num_microseconds(&self) -> Option<i64>333 pub const fn num_microseconds(&self) -> Option<i64> {
334 let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
335 let nanos_part = self.subsec_nanos() / NANOS_PER_MICRO;
336 secs_part.checked_add(nanos_part as i64)
337 }
338
339 /// Returns the total number of whole nanoseconds in the `TimeDelta`,
340 /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
num_nanoseconds(&self) -> Option<i64>341 pub const fn num_nanoseconds(&self) -> Option<i64> {
342 let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
343 let nanos_part = self.subsec_nanos();
344 secs_part.checked_add(nanos_part as i64)
345 }
346
347 /// Add two `TimeDelta`s, returning `None` if overflow occurred.
348 #[must_use]
checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta>349 pub const fn checked_add(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
350 // No overflow checks here because we stay comfortably within the range of an `i64`.
351 // Range checks happen in `TimeDelta::new`.
352 let mut secs = self.secs + rhs.secs;
353 let mut nanos = self.nanos + rhs.nanos;
354 if nanos >= NANOS_PER_SEC {
355 nanos -= NANOS_PER_SEC;
356 secs += 1;
357 }
358 TimeDelta::new(secs, nanos as u32)
359 }
360
361 /// Subtract two `TimeDelta`s, returning `None` if overflow occurred.
362 #[must_use]
checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta>363 pub const fn checked_sub(&self, rhs: &TimeDelta) -> Option<TimeDelta> {
364 // No overflow checks here because we stay comfortably within the range of an `i64`.
365 // Range checks happen in `TimeDelta::new`.
366 let mut secs = self.secs - rhs.secs;
367 let mut nanos = self.nanos - rhs.nanos;
368 if nanos < 0 {
369 nanos += NANOS_PER_SEC;
370 secs -= 1;
371 }
372 TimeDelta::new(secs, nanos as u32)
373 }
374
375 /// Returns the `TimeDelta` as an absolute (non-negative) value.
376 #[inline]
abs(&self) -> TimeDelta377 pub const fn abs(&self) -> TimeDelta {
378 if self.secs < 0 && self.nanos != 0 {
379 TimeDelta { secs: (self.secs + 1).abs(), nanos: NANOS_PER_SEC - self.nanos }
380 } else {
381 TimeDelta { secs: self.secs.abs(), nanos: self.nanos }
382 }
383 }
384
385 /// The minimum possible `TimeDelta`: `-i64::MAX` milliseconds.
386 #[inline]
min_value() -> TimeDelta387 pub const fn min_value() -> TimeDelta {
388 MIN
389 }
390
391 /// The maximum possible `TimeDelta`: `i64::MAX` milliseconds.
392 #[inline]
max_value() -> TimeDelta393 pub const fn max_value() -> TimeDelta {
394 MAX
395 }
396
397 /// A `TimeDelta` where the stored seconds and nanoseconds are equal to zero.
398 #[inline]
zero() -> TimeDelta399 pub const fn zero() -> TimeDelta {
400 TimeDelta { secs: 0, nanos: 0 }
401 }
402
403 /// Returns `true` if the `TimeDelta` equals `TimeDelta::zero()`.
404 #[inline]
is_zero(&self) -> bool405 pub const fn is_zero(&self) -> bool {
406 self.secs == 0 && self.nanos == 0
407 }
408
409 /// Creates a `TimeDelta` object from `std::time::Duration`
410 ///
411 /// This function errors when original duration is larger than the maximum
412 /// value supported for this type.
from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError>413 pub const fn from_std(duration: Duration) -> Result<TimeDelta, OutOfRangeError> {
414 // We need to check secs as u64 before coercing to i64
415 if duration.as_secs() > MAX.secs as u64 {
416 return Err(OutOfRangeError(()));
417 }
418 match TimeDelta::new(duration.as_secs() as i64, duration.subsec_nanos()) {
419 Some(d) => Ok(d),
420 None => Err(OutOfRangeError(())),
421 }
422 }
423
424 /// Creates a `std::time::Duration` object from a `TimeDelta`.
425 ///
426 /// This function errors when duration is less than zero. As standard
427 /// library implementation is limited to non-negative values.
to_std(&self) -> Result<Duration, OutOfRangeError>428 pub const fn to_std(&self) -> Result<Duration, OutOfRangeError> {
429 if self.secs < 0 {
430 return Err(OutOfRangeError(()));
431 }
432 Ok(Duration::new(self.secs as u64, self.nanos as u32))
433 }
434
435 /// This duplicates `Neg::neg` because trait methods can't be const yet.
neg(self) -> TimeDelta436 pub(crate) const fn neg(self) -> TimeDelta {
437 let (secs_diff, nanos) = match self.nanos {
438 0 => (0, 0),
439 nanos => (1, NANOS_PER_SEC - nanos),
440 };
441 TimeDelta { secs: -self.secs - secs_diff, nanos }
442 }
443 }
444
445 impl Neg for TimeDelta {
446 type Output = TimeDelta;
447
448 #[inline]
neg(self) -> TimeDelta449 fn neg(self) -> TimeDelta {
450 let (secs_diff, nanos) = match self.nanos {
451 0 => (0, 0),
452 nanos => (1, NANOS_PER_SEC - nanos),
453 };
454 TimeDelta { secs: -self.secs - secs_diff, nanos }
455 }
456 }
457
458 impl Add for TimeDelta {
459 type Output = TimeDelta;
460
add(self, rhs: TimeDelta) -> TimeDelta461 fn add(self, rhs: TimeDelta) -> TimeDelta {
462 self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed")
463 }
464 }
465
466 impl Sub for TimeDelta {
467 type Output = TimeDelta;
468
sub(self, rhs: TimeDelta) -> TimeDelta469 fn sub(self, rhs: TimeDelta) -> TimeDelta {
470 self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed")
471 }
472 }
473
474 impl AddAssign for TimeDelta {
add_assign(&mut self, rhs: TimeDelta)475 fn add_assign(&mut self, rhs: TimeDelta) {
476 let new = self.checked_add(&rhs).expect("`TimeDelta + TimeDelta` overflowed");
477 *self = new;
478 }
479 }
480
481 impl SubAssign for TimeDelta {
sub_assign(&mut self, rhs: TimeDelta)482 fn sub_assign(&mut self, rhs: TimeDelta) {
483 let new = self.checked_sub(&rhs).expect("`TimeDelta - TimeDelta` overflowed");
484 *self = new;
485 }
486 }
487
488 impl Mul<i32> for TimeDelta {
489 type Output = TimeDelta;
490
mul(self, rhs: i32) -> TimeDelta491 fn mul(self, rhs: i32) -> TimeDelta {
492 // Multiply nanoseconds as i64, because it cannot overflow that way.
493 let total_nanos = self.nanos as i64 * rhs as i64;
494 let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
495 let secs = self.secs * rhs as i64 + extra_secs;
496 TimeDelta { secs, nanos: nanos as i32 }
497 }
498 }
499
500 impl Div<i32> for TimeDelta {
501 type Output = TimeDelta;
502
div(self, rhs: i32) -> TimeDelta503 fn div(self, rhs: i32) -> TimeDelta {
504 let mut secs = self.secs / rhs as i64;
505 let carry = self.secs - secs * rhs as i64;
506 let extra_nanos = carry * NANOS_PER_SEC as i64 / rhs as i64;
507 let mut nanos = self.nanos / rhs + extra_nanos as i32;
508 if nanos >= NANOS_PER_SEC {
509 nanos -= NANOS_PER_SEC;
510 secs += 1;
511 }
512 if nanos < 0 {
513 nanos += NANOS_PER_SEC;
514 secs -= 1;
515 }
516 TimeDelta { secs, nanos }
517 }
518 }
519
520 impl<'a> core::iter::Sum<&'a TimeDelta> for TimeDelta {
sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta521 fn sum<I: Iterator<Item = &'a TimeDelta>>(iter: I) -> TimeDelta {
522 iter.fold(TimeDelta::zero(), |acc, x| acc + *x)
523 }
524 }
525
526 impl core::iter::Sum<TimeDelta> for TimeDelta {
sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta527 fn sum<I: Iterator<Item = TimeDelta>>(iter: I) -> TimeDelta {
528 iter.fold(TimeDelta::zero(), |acc, x| acc + x)
529 }
530 }
531
532 impl fmt::Display for TimeDelta {
533 /// Format a `TimeDelta` using the [ISO 8601] format
534 ///
535 /// [ISO 8601]: https://en.wikipedia.org/wiki/ISO_8601#Durations
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result536 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
537 // technically speaking, negative duration is not valid ISO 8601,
538 // but we need to print it anyway.
539 let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") };
540
541 write!(f, "{}P", sign)?;
542 // Plenty of ways to encode an empty string. `P0D` is short and not too strange.
543 if abs.secs == 0 && abs.nanos == 0 {
544 return f.write_str("0D");
545 }
546
547 f.write_fmt(format_args!("T{}", abs.secs))?;
548
549 if abs.nanos > 0 {
550 // Count the number of significant digits, while removing all trailing zero's.
551 let mut figures = 9usize;
552 let mut fraction_digits = abs.nanos;
553 loop {
554 let div = fraction_digits / 10;
555 let last_digit = fraction_digits % 10;
556 if last_digit != 0 {
557 break;
558 }
559 fraction_digits = div;
560 figures -= 1;
561 }
562 f.write_fmt(format_args!(".{:01$}", fraction_digits, figures))?;
563 }
564 f.write_str("S")?;
565 Ok(())
566 }
567 }
568
569 /// Represents error when converting `TimeDelta` to/from a standard library
570 /// implementation
571 ///
572 /// The `std::time::Duration` supports a range from zero to `u64::MAX`
573 /// *seconds*, while this module supports signed range of up to
574 /// `i64::MAX` of *milliseconds*.
575 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
576 pub struct OutOfRangeError(());
577
578 impl fmt::Display for OutOfRangeError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result579 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
580 write!(f, "Source duration value is out of range for the target type")
581 }
582 }
583
584 #[cfg(feature = "std")]
585 impl Error for OutOfRangeError {
586 #[allow(deprecated)]
description(&self) -> &str587 fn description(&self) -> &str {
588 "out of range error"
589 }
590 }
591
592 #[inline]
div_mod_floor_64(this: i64, other: i64) -> (i64, i64)593 const fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
594 (this.div_euclid(other), this.rem_euclid(other))
595 }
596
597 #[cfg(all(feature = "arbitrary", feature = "std"))]
598 impl arbitrary::Arbitrary<'_> for TimeDelta {
arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta>599 fn arbitrary(u: &mut arbitrary::Unstructured) -> arbitrary::Result<TimeDelta> {
600 const MIN_SECS: i64 = -i64::MAX / MILLIS_PER_SEC - 1;
601 const MAX_SECS: i64 = i64::MAX / MILLIS_PER_SEC;
602
603 let secs: i64 = u.int_in_range(MIN_SECS..=MAX_SECS)?;
604 let nanos: i32 = u.int_in_range(0..=(NANOS_PER_SEC - 1))?;
605 let duration = TimeDelta { secs, nanos };
606
607 if duration < MIN || duration > MAX {
608 Err(arbitrary::Error::IncorrectFormat)
609 } else {
610 Ok(duration)
611 }
612 }
613 }
614
615 #[cfg(test)]
616 mod tests {
617 use super::OutOfRangeError;
618 use super::{TimeDelta, MAX, MIN};
619 use core::time::Duration;
620
621 #[test]
test_duration()622 fn test_duration() {
623 assert!(TimeDelta::seconds(1) != TimeDelta::zero());
624 assert_eq!(TimeDelta::seconds(1) + TimeDelta::seconds(2), TimeDelta::seconds(3));
625 assert_eq!(
626 TimeDelta::seconds(86_399) + TimeDelta::seconds(4),
627 TimeDelta::days(1) + TimeDelta::seconds(3)
628 );
629 assert_eq!(TimeDelta::days(10) - TimeDelta::seconds(1000), TimeDelta::seconds(863_000));
630 assert_eq!(
631 TimeDelta::days(10) - TimeDelta::seconds(1_000_000),
632 TimeDelta::seconds(-136_000)
633 );
634 assert_eq!(
635 TimeDelta::days(2) + TimeDelta::seconds(86_399) + TimeDelta::nanoseconds(1_234_567_890),
636 TimeDelta::days(3) + TimeDelta::nanoseconds(234_567_890)
637 );
638 assert_eq!(-TimeDelta::days(3), TimeDelta::days(-3));
639 assert_eq!(
640 -(TimeDelta::days(3) + TimeDelta::seconds(70)),
641 TimeDelta::days(-4) + TimeDelta::seconds(86_400 - 70)
642 );
643
644 let mut d = TimeDelta::default();
645 d += TimeDelta::minutes(1);
646 d -= TimeDelta::seconds(30);
647 assert_eq!(d, TimeDelta::seconds(30));
648 }
649
650 #[test]
test_duration_num_days()651 fn test_duration_num_days() {
652 assert_eq!(TimeDelta::zero().num_days(), 0);
653 assert_eq!(TimeDelta::days(1).num_days(), 1);
654 assert_eq!(TimeDelta::days(-1).num_days(), -1);
655 assert_eq!(TimeDelta::seconds(86_399).num_days(), 0);
656 assert_eq!(TimeDelta::seconds(86_401).num_days(), 1);
657 assert_eq!(TimeDelta::seconds(-86_399).num_days(), 0);
658 assert_eq!(TimeDelta::seconds(-86_401).num_days(), -1);
659 assert_eq!(TimeDelta::days(i32::MAX as i64).num_days(), i32::MAX as i64);
660 assert_eq!(TimeDelta::days(i32::MIN as i64).num_days(), i32::MIN as i64);
661 }
662
663 #[test]
test_duration_num_seconds()664 fn test_duration_num_seconds() {
665 assert_eq!(TimeDelta::zero().num_seconds(), 0);
666 assert_eq!(TimeDelta::seconds(1).num_seconds(), 1);
667 assert_eq!(TimeDelta::seconds(-1).num_seconds(), -1);
668 assert_eq!(TimeDelta::milliseconds(999).num_seconds(), 0);
669 assert_eq!(TimeDelta::milliseconds(1001).num_seconds(), 1);
670 assert_eq!(TimeDelta::milliseconds(-999).num_seconds(), 0);
671 assert_eq!(TimeDelta::milliseconds(-1001).num_seconds(), -1);
672 }
673 #[test]
test_duration_seconds_max_allowed()674 fn test_duration_seconds_max_allowed() {
675 let duration = TimeDelta::seconds(i64::MAX / 1_000);
676 assert_eq!(duration.num_seconds(), i64::MAX / 1_000);
677 assert_eq!(
678 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
679 i64::MAX as i128 / 1_000 * 1_000_000_000
680 );
681 }
682 #[test]
test_duration_seconds_max_overflow()683 fn test_duration_seconds_max_overflow() {
684 assert!(TimeDelta::try_seconds(i64::MAX / 1_000 + 1).is_none());
685 }
686 #[test]
687 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
test_duration_seconds_max_overflow_panic()688 fn test_duration_seconds_max_overflow_panic() {
689 let _ = TimeDelta::seconds(i64::MAX / 1_000 + 1);
690 }
691 #[test]
test_duration_seconds_min_allowed()692 fn test_duration_seconds_min_allowed() {
693 let duration = TimeDelta::seconds(i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding
694 assert_eq!(duration.num_seconds(), i64::MIN / 1_000); // Same as -i64::MAX / 1_000 due to rounding
695 assert_eq!(
696 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
697 -i64::MAX as i128 / 1_000 * 1_000_000_000
698 );
699 }
700 #[test]
test_duration_seconds_min_underflow()701 fn test_duration_seconds_min_underflow() {
702 assert!(TimeDelta::try_seconds(-i64::MAX / 1_000 - 1).is_none());
703 }
704 #[test]
705 #[should_panic(expected = "TimeDelta::seconds out of bounds")]
test_duration_seconds_min_underflow_panic()706 fn test_duration_seconds_min_underflow_panic() {
707 let _ = TimeDelta::seconds(-i64::MAX / 1_000 - 1);
708 }
709
710 #[test]
test_duration_num_milliseconds()711 fn test_duration_num_milliseconds() {
712 assert_eq!(TimeDelta::zero().num_milliseconds(), 0);
713 assert_eq!(TimeDelta::milliseconds(1).num_milliseconds(), 1);
714 assert_eq!(TimeDelta::milliseconds(-1).num_milliseconds(), -1);
715 assert_eq!(TimeDelta::microseconds(999).num_milliseconds(), 0);
716 assert_eq!(TimeDelta::microseconds(1001).num_milliseconds(), 1);
717 assert_eq!(TimeDelta::microseconds(-999).num_milliseconds(), 0);
718 assert_eq!(TimeDelta::microseconds(-1001).num_milliseconds(), -1);
719 }
720 #[test]
test_duration_milliseconds_max_allowed()721 fn test_duration_milliseconds_max_allowed() {
722 // The maximum number of milliseconds acceptable through the constructor is
723 // equal to the number that can be stored in a TimeDelta.
724 let duration = TimeDelta::milliseconds(i64::MAX);
725 assert_eq!(duration.num_milliseconds(), i64::MAX);
726 assert_eq!(
727 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
728 i64::MAX as i128 * 1_000_000
729 );
730 }
731 #[test]
test_duration_milliseconds_max_overflow()732 fn test_duration_milliseconds_max_overflow() {
733 // Here we ensure that trying to add one millisecond to the maximum storable
734 // value will fail.
735 assert!(TimeDelta::milliseconds(i64::MAX)
736 .checked_add(&TimeDelta::milliseconds(1))
737 .is_none());
738 }
739 #[test]
test_duration_milliseconds_min_allowed()740 fn test_duration_milliseconds_min_allowed() {
741 // The minimum number of milliseconds acceptable through the constructor is
742 // not equal to the number that can be stored in a TimeDelta - there is a
743 // difference of one (i64::MIN vs -i64::MAX).
744 let duration = TimeDelta::milliseconds(-i64::MAX);
745 assert_eq!(duration.num_milliseconds(), -i64::MAX);
746 assert_eq!(
747 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
748 -i64::MAX as i128 * 1_000_000
749 );
750 }
751 #[test]
test_duration_milliseconds_min_underflow()752 fn test_duration_milliseconds_min_underflow() {
753 // Here we ensure that trying to subtract one millisecond from the minimum
754 // storable value will fail.
755 assert!(TimeDelta::milliseconds(-i64::MAX)
756 .checked_sub(&TimeDelta::milliseconds(1))
757 .is_none());
758 }
759 #[test]
760 #[should_panic(expected = "TimeDelta::milliseconds out of bounds")]
test_duration_milliseconds_min_underflow_panic()761 fn test_duration_milliseconds_min_underflow_panic() {
762 // Here we ensure that trying to create a value one millisecond below the
763 // minimum storable value will fail. This test is necessary because the
764 // storable range is -i64::MAX, but the constructor type of i64 will allow
765 // i64::MIN, which is one value below.
766 let _ = TimeDelta::milliseconds(i64::MIN); // Same as -i64::MAX - 1
767 }
768
769 #[test]
test_duration_num_microseconds()770 fn test_duration_num_microseconds() {
771 assert_eq!(TimeDelta::zero().num_microseconds(), Some(0));
772 assert_eq!(TimeDelta::microseconds(1).num_microseconds(), Some(1));
773 assert_eq!(TimeDelta::microseconds(-1).num_microseconds(), Some(-1));
774 assert_eq!(TimeDelta::nanoseconds(999).num_microseconds(), Some(0));
775 assert_eq!(TimeDelta::nanoseconds(1001).num_microseconds(), Some(1));
776 assert_eq!(TimeDelta::nanoseconds(-999).num_microseconds(), Some(0));
777 assert_eq!(TimeDelta::nanoseconds(-1001).num_microseconds(), Some(-1));
778
779 // overflow checks
780 const MICROS_PER_DAY: i64 = 86_400_000_000;
781 assert_eq!(
782 TimeDelta::days(i64::MAX / MICROS_PER_DAY).num_microseconds(),
783 Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
784 );
785 assert_eq!(
786 TimeDelta::days(-i64::MAX / MICROS_PER_DAY).num_microseconds(),
787 Some(-i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)
788 );
789 assert_eq!(TimeDelta::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None);
790 assert_eq!(TimeDelta::days(-i64::MAX / MICROS_PER_DAY - 1).num_microseconds(), None);
791 }
792 #[test]
test_duration_microseconds_max_allowed()793 fn test_duration_microseconds_max_allowed() {
794 // The number of microseconds acceptable through the constructor is far
795 // fewer than the number that can actually be stored in a TimeDelta, so this
796 // is not a particular insightful test.
797 let duration = TimeDelta::microseconds(i64::MAX);
798 assert_eq!(duration.num_microseconds(), Some(i64::MAX));
799 assert_eq!(
800 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
801 i64::MAX as i128 * 1_000
802 );
803 // Here we create a TimeDelta with the maximum possible number of
804 // microseconds by creating a TimeDelta with the maximum number of
805 // milliseconds and then checking that the number of microseconds matches
806 // the storage limit.
807 let duration = TimeDelta::milliseconds(i64::MAX);
808 assert!(duration.num_microseconds().is_none());
809 assert_eq!(
810 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
811 i64::MAX as i128 * 1_000_000
812 );
813 }
814 #[test]
test_duration_microseconds_max_overflow()815 fn test_duration_microseconds_max_overflow() {
816 // This test establishes that a TimeDelta can store more microseconds than
817 // are representable through the return of duration.num_microseconds().
818 let duration = TimeDelta::microseconds(i64::MAX) + TimeDelta::microseconds(1);
819 assert!(duration.num_microseconds().is_none());
820 assert_eq!(
821 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
822 (i64::MAX as i128 + 1) * 1_000
823 );
824 // Here we ensure that trying to add one microsecond to the maximum storable
825 // value will fail.
826 assert!(TimeDelta::milliseconds(i64::MAX)
827 .checked_add(&TimeDelta::microseconds(1))
828 .is_none());
829 }
830 #[test]
test_duration_microseconds_min_allowed()831 fn test_duration_microseconds_min_allowed() {
832 // The number of microseconds acceptable through the constructor is far
833 // fewer than the number that can actually be stored in a TimeDelta, so this
834 // is not a particular insightful test.
835 let duration = TimeDelta::microseconds(i64::MIN);
836 assert_eq!(duration.num_microseconds(), Some(i64::MIN));
837 assert_eq!(
838 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
839 i64::MIN as i128 * 1_000
840 );
841 // Here we create a TimeDelta with the minimum possible number of
842 // microseconds by creating a TimeDelta with the minimum number of
843 // milliseconds and then checking that the number of microseconds matches
844 // the storage limit.
845 let duration = TimeDelta::milliseconds(-i64::MAX);
846 assert!(duration.num_microseconds().is_none());
847 assert_eq!(
848 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
849 -i64::MAX as i128 * 1_000_000
850 );
851 }
852 #[test]
test_duration_microseconds_min_underflow()853 fn test_duration_microseconds_min_underflow() {
854 // This test establishes that a TimeDelta can store more microseconds than
855 // are representable through the return of duration.num_microseconds().
856 let duration = TimeDelta::microseconds(i64::MIN) - TimeDelta::microseconds(1);
857 assert!(duration.num_microseconds().is_none());
858 assert_eq!(
859 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
860 (i64::MIN as i128 - 1) * 1_000
861 );
862 // Here we ensure that trying to subtract one microsecond from the minimum
863 // storable value will fail.
864 assert!(TimeDelta::milliseconds(-i64::MAX)
865 .checked_sub(&TimeDelta::microseconds(1))
866 .is_none());
867 }
868
869 #[test]
test_duration_num_nanoseconds()870 fn test_duration_num_nanoseconds() {
871 assert_eq!(TimeDelta::zero().num_nanoseconds(), Some(0));
872 assert_eq!(TimeDelta::nanoseconds(1).num_nanoseconds(), Some(1));
873 assert_eq!(TimeDelta::nanoseconds(-1).num_nanoseconds(), Some(-1));
874
875 // overflow checks
876 const NANOS_PER_DAY: i64 = 86_400_000_000_000;
877 assert_eq!(
878 TimeDelta::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
879 Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
880 );
881 assert_eq!(
882 TimeDelta::days(-i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
883 Some(-i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)
884 );
885 assert_eq!(TimeDelta::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None);
886 assert_eq!(TimeDelta::days(-i64::MAX / NANOS_PER_DAY - 1).num_nanoseconds(), None);
887 }
888 #[test]
test_duration_nanoseconds_max_allowed()889 fn test_duration_nanoseconds_max_allowed() {
890 // The number of nanoseconds acceptable through the constructor is far fewer
891 // than the number that can actually be stored in a TimeDelta, so this is not
892 // a particular insightful test.
893 let duration = TimeDelta::nanoseconds(i64::MAX);
894 assert_eq!(duration.num_nanoseconds(), Some(i64::MAX));
895 assert_eq!(
896 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
897 i64::MAX as i128
898 );
899 // Here we create a TimeDelta with the maximum possible number of nanoseconds
900 // by creating a TimeDelta with the maximum number of milliseconds and then
901 // checking that the number of nanoseconds matches the storage limit.
902 let duration = TimeDelta::milliseconds(i64::MAX);
903 assert!(duration.num_nanoseconds().is_none());
904 assert_eq!(
905 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
906 i64::MAX as i128 * 1_000_000
907 );
908 }
909 #[test]
test_duration_nanoseconds_max_overflow()910 fn test_duration_nanoseconds_max_overflow() {
911 // This test establishes that a TimeDelta can store more nanoseconds than are
912 // representable through the return of duration.num_nanoseconds().
913 let duration = TimeDelta::nanoseconds(i64::MAX) + TimeDelta::nanoseconds(1);
914 assert!(duration.num_nanoseconds().is_none());
915 assert_eq!(
916 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
917 i64::MAX as i128 + 1
918 );
919 // Here we ensure that trying to add one nanosecond to the maximum storable
920 // value will fail.
921 assert!(TimeDelta::milliseconds(i64::MAX)
922 .checked_add(&TimeDelta::nanoseconds(1))
923 .is_none());
924 }
925 #[test]
test_duration_nanoseconds_min_allowed()926 fn test_duration_nanoseconds_min_allowed() {
927 // The number of nanoseconds acceptable through the constructor is far fewer
928 // than the number that can actually be stored in a TimeDelta, so this is not
929 // a particular insightful test.
930 let duration = TimeDelta::nanoseconds(i64::MIN);
931 assert_eq!(duration.num_nanoseconds(), Some(i64::MIN));
932 assert_eq!(
933 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
934 i64::MIN as i128
935 );
936 // Here we create a TimeDelta with the minimum possible number of nanoseconds
937 // by creating a TimeDelta with the minimum number of milliseconds and then
938 // checking that the number of nanoseconds matches the storage limit.
939 let duration = TimeDelta::milliseconds(-i64::MAX);
940 assert!(duration.num_nanoseconds().is_none());
941 assert_eq!(
942 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
943 -i64::MAX as i128 * 1_000_000
944 );
945 }
946 #[test]
test_duration_nanoseconds_min_underflow()947 fn test_duration_nanoseconds_min_underflow() {
948 // This test establishes that a TimeDelta can store more nanoseconds than are
949 // representable through the return of duration.num_nanoseconds().
950 let duration = TimeDelta::nanoseconds(i64::MIN) - TimeDelta::nanoseconds(1);
951 assert!(duration.num_nanoseconds().is_none());
952 assert_eq!(
953 duration.secs as i128 * 1_000_000_000 + duration.nanos as i128,
954 i64::MIN as i128 - 1
955 );
956 // Here we ensure that trying to subtract one nanosecond from the minimum
957 // storable value will fail.
958 assert!(TimeDelta::milliseconds(-i64::MAX)
959 .checked_sub(&TimeDelta::nanoseconds(1))
960 .is_none());
961 }
962
963 #[test]
test_max()964 fn test_max() {
965 assert_eq!(
966 MAX.secs as i128 * 1_000_000_000 + MAX.nanos as i128,
967 i64::MAX as i128 * 1_000_000
968 );
969 assert_eq!(MAX, TimeDelta::milliseconds(i64::MAX));
970 assert_eq!(MAX.num_milliseconds(), i64::MAX);
971 assert_eq!(MAX.num_microseconds(), None);
972 assert_eq!(MAX.num_nanoseconds(), None);
973 }
974 #[test]
test_min()975 fn test_min() {
976 assert_eq!(
977 MIN.secs as i128 * 1_000_000_000 + MIN.nanos as i128,
978 -i64::MAX as i128 * 1_000_000
979 );
980 assert_eq!(MIN, TimeDelta::milliseconds(-i64::MAX));
981 assert_eq!(MIN.num_milliseconds(), -i64::MAX);
982 assert_eq!(MIN.num_microseconds(), None);
983 assert_eq!(MIN.num_nanoseconds(), None);
984 }
985
986 #[test]
test_duration_ord()987 fn test_duration_ord() {
988 assert!(TimeDelta::milliseconds(1) < TimeDelta::milliseconds(2));
989 assert!(TimeDelta::milliseconds(2) > TimeDelta::milliseconds(1));
990 assert!(TimeDelta::milliseconds(-1) > TimeDelta::milliseconds(-2));
991 assert!(TimeDelta::milliseconds(-2) < TimeDelta::milliseconds(-1));
992 assert!(TimeDelta::milliseconds(-1) < TimeDelta::milliseconds(1));
993 assert!(TimeDelta::milliseconds(1) > TimeDelta::milliseconds(-1));
994 assert!(TimeDelta::milliseconds(0) < TimeDelta::milliseconds(1));
995 assert!(TimeDelta::milliseconds(0) > TimeDelta::milliseconds(-1));
996 assert!(TimeDelta::milliseconds(1_001) < TimeDelta::milliseconds(1_002));
997 assert!(TimeDelta::milliseconds(-1_001) > TimeDelta::milliseconds(-1_002));
998 assert!(TimeDelta::nanoseconds(1_234_567_890) < TimeDelta::nanoseconds(1_234_567_891));
999 assert!(TimeDelta::nanoseconds(-1_234_567_890) > TimeDelta::nanoseconds(-1_234_567_891));
1000 assert!(TimeDelta::milliseconds(i64::MAX) > TimeDelta::milliseconds(i64::MAX - 1));
1001 assert!(TimeDelta::milliseconds(-i64::MAX) < TimeDelta::milliseconds(-i64::MAX + 1));
1002 }
1003
1004 #[test]
test_duration_checked_ops()1005 fn test_duration_checked_ops() {
1006 assert_eq!(
1007 TimeDelta::milliseconds(i64::MAX).checked_add(&TimeDelta::milliseconds(0)),
1008 Some(TimeDelta::milliseconds(i64::MAX))
1009 );
1010 assert_eq!(
1011 TimeDelta::milliseconds(i64::MAX - 1).checked_add(&TimeDelta::microseconds(999)),
1012 Some(TimeDelta::milliseconds(i64::MAX - 2) + TimeDelta::microseconds(1999))
1013 );
1014 assert!(TimeDelta::milliseconds(i64::MAX)
1015 .checked_add(&TimeDelta::microseconds(1000))
1016 .is_none());
1017 assert!(TimeDelta::milliseconds(i64::MAX)
1018 .checked_add(&TimeDelta::nanoseconds(1))
1019 .is_none());
1020
1021 assert_eq!(
1022 TimeDelta::milliseconds(-i64::MAX).checked_sub(&TimeDelta::milliseconds(0)),
1023 Some(TimeDelta::milliseconds(-i64::MAX))
1024 );
1025 assert_eq!(
1026 TimeDelta::milliseconds(-i64::MAX + 1).checked_sub(&TimeDelta::microseconds(999)),
1027 Some(TimeDelta::milliseconds(-i64::MAX + 2) - TimeDelta::microseconds(1999))
1028 );
1029 assert!(TimeDelta::milliseconds(-i64::MAX)
1030 .checked_sub(&TimeDelta::milliseconds(1))
1031 .is_none());
1032 assert!(TimeDelta::milliseconds(-i64::MAX)
1033 .checked_sub(&TimeDelta::nanoseconds(1))
1034 .is_none());
1035 }
1036
1037 #[test]
test_duration_abs()1038 fn test_duration_abs() {
1039 assert_eq!(TimeDelta::milliseconds(1300).abs(), TimeDelta::milliseconds(1300));
1040 assert_eq!(TimeDelta::milliseconds(1000).abs(), TimeDelta::milliseconds(1000));
1041 assert_eq!(TimeDelta::milliseconds(300).abs(), TimeDelta::milliseconds(300));
1042 assert_eq!(TimeDelta::milliseconds(0).abs(), TimeDelta::milliseconds(0));
1043 assert_eq!(TimeDelta::milliseconds(-300).abs(), TimeDelta::milliseconds(300));
1044 assert_eq!(TimeDelta::milliseconds(-700).abs(), TimeDelta::milliseconds(700));
1045 assert_eq!(TimeDelta::milliseconds(-1000).abs(), TimeDelta::milliseconds(1000));
1046 assert_eq!(TimeDelta::milliseconds(-1300).abs(), TimeDelta::milliseconds(1300));
1047 assert_eq!(TimeDelta::milliseconds(-1700).abs(), TimeDelta::milliseconds(1700));
1048 assert_eq!(TimeDelta::milliseconds(-i64::MAX).abs(), TimeDelta::milliseconds(i64::MAX));
1049 }
1050
1051 #[test]
1052 #[allow(clippy::erasing_op)]
test_duration_mul()1053 fn test_duration_mul() {
1054 assert_eq!(TimeDelta::zero() * i32::MAX, TimeDelta::zero());
1055 assert_eq!(TimeDelta::zero() * i32::MIN, TimeDelta::zero());
1056 assert_eq!(TimeDelta::nanoseconds(1) * 0, TimeDelta::zero());
1057 assert_eq!(TimeDelta::nanoseconds(1) * 1, TimeDelta::nanoseconds(1));
1058 assert_eq!(TimeDelta::nanoseconds(1) * 1_000_000_000, TimeDelta::seconds(1));
1059 assert_eq!(TimeDelta::nanoseconds(1) * -1_000_000_000, -TimeDelta::seconds(1));
1060 assert_eq!(-TimeDelta::nanoseconds(1) * 1_000_000_000, -TimeDelta::seconds(1));
1061 assert_eq!(
1062 TimeDelta::nanoseconds(30) * 333_333_333,
1063 TimeDelta::seconds(10) - TimeDelta::nanoseconds(10)
1064 );
1065 assert_eq!(
1066 (TimeDelta::nanoseconds(1) + TimeDelta::seconds(1) + TimeDelta::days(1)) * 3,
1067 TimeDelta::nanoseconds(3) + TimeDelta::seconds(3) + TimeDelta::days(3)
1068 );
1069 assert_eq!(TimeDelta::milliseconds(1500) * -2, TimeDelta::seconds(-3));
1070 assert_eq!(TimeDelta::milliseconds(-1500) * 2, TimeDelta::seconds(-3));
1071 }
1072
1073 #[test]
test_duration_div()1074 fn test_duration_div() {
1075 assert_eq!(TimeDelta::zero() / i32::MAX, TimeDelta::zero());
1076 assert_eq!(TimeDelta::zero() / i32::MIN, TimeDelta::zero());
1077 assert_eq!(TimeDelta::nanoseconds(123_456_789) / 1, TimeDelta::nanoseconds(123_456_789));
1078 assert_eq!(TimeDelta::nanoseconds(123_456_789) / -1, -TimeDelta::nanoseconds(123_456_789));
1079 assert_eq!(-TimeDelta::nanoseconds(123_456_789) / -1, TimeDelta::nanoseconds(123_456_789));
1080 assert_eq!(-TimeDelta::nanoseconds(123_456_789) / 1, -TimeDelta::nanoseconds(123_456_789));
1081 assert_eq!(TimeDelta::seconds(1) / 3, TimeDelta::nanoseconds(333_333_333));
1082 assert_eq!(TimeDelta::seconds(4) / 3, TimeDelta::nanoseconds(1_333_333_333));
1083 assert_eq!(TimeDelta::seconds(-1) / 2, TimeDelta::milliseconds(-500));
1084 assert_eq!(TimeDelta::seconds(1) / -2, TimeDelta::milliseconds(-500));
1085 assert_eq!(TimeDelta::seconds(-1) / -2, TimeDelta::milliseconds(500));
1086 assert_eq!(TimeDelta::seconds(-4) / 3, TimeDelta::nanoseconds(-1_333_333_333));
1087 assert_eq!(TimeDelta::seconds(-4) / -3, TimeDelta::nanoseconds(1_333_333_333));
1088 }
1089
1090 #[test]
test_duration_sum()1091 fn test_duration_sum() {
1092 let duration_list_1 = [TimeDelta::zero(), TimeDelta::seconds(1)];
1093 let sum_1: TimeDelta = duration_list_1.iter().sum();
1094 assert_eq!(sum_1, TimeDelta::seconds(1));
1095
1096 let duration_list_2 = [
1097 TimeDelta::zero(),
1098 TimeDelta::seconds(1),
1099 TimeDelta::seconds(6),
1100 TimeDelta::seconds(10),
1101 ];
1102 let sum_2: TimeDelta = duration_list_2.iter().sum();
1103 assert_eq!(sum_2, TimeDelta::seconds(17));
1104
1105 let duration_arr = [
1106 TimeDelta::zero(),
1107 TimeDelta::seconds(1),
1108 TimeDelta::seconds(6),
1109 TimeDelta::seconds(10),
1110 ];
1111 let sum_3: TimeDelta = duration_arr.into_iter().sum();
1112 assert_eq!(sum_3, TimeDelta::seconds(17));
1113 }
1114
1115 #[test]
test_duration_fmt()1116 fn test_duration_fmt() {
1117 assert_eq!(TimeDelta::zero().to_string(), "P0D");
1118 assert_eq!(TimeDelta::days(42).to_string(), "PT3628800S");
1119 assert_eq!(TimeDelta::days(-42).to_string(), "-PT3628800S");
1120 assert_eq!(TimeDelta::seconds(42).to_string(), "PT42S");
1121 assert_eq!(TimeDelta::milliseconds(42).to_string(), "PT0.042S");
1122 assert_eq!(TimeDelta::microseconds(42).to_string(), "PT0.000042S");
1123 assert_eq!(TimeDelta::nanoseconds(42).to_string(), "PT0.000000042S");
1124 assert_eq!(
1125 (TimeDelta::days(7) + TimeDelta::milliseconds(6543)).to_string(),
1126 "PT604806.543S"
1127 );
1128 assert_eq!(TimeDelta::seconds(-86_401).to_string(), "-PT86401S");
1129 assert_eq!(TimeDelta::nanoseconds(-1).to_string(), "-PT0.000000001S");
1130
1131 // the format specifier should have no effect on `TimeDelta`
1132 assert_eq!(
1133 format!("{:30}", TimeDelta::days(1) + TimeDelta::milliseconds(2345)),
1134 "PT86402.345S"
1135 );
1136 }
1137
1138 #[test]
test_to_std()1139 fn test_to_std() {
1140 assert_eq!(TimeDelta::seconds(1).to_std(), Ok(Duration::new(1, 0)));
1141 assert_eq!(TimeDelta::seconds(86_401).to_std(), Ok(Duration::new(86_401, 0)));
1142 assert_eq!(TimeDelta::milliseconds(123).to_std(), Ok(Duration::new(0, 123_000_000)));
1143 assert_eq!(TimeDelta::milliseconds(123_765).to_std(), Ok(Duration::new(123, 765_000_000)));
1144 assert_eq!(TimeDelta::nanoseconds(777).to_std(), Ok(Duration::new(0, 777)));
1145 assert_eq!(MAX.to_std(), Ok(Duration::new(9_223_372_036_854_775, 807_000_000)));
1146 assert_eq!(TimeDelta::seconds(-1).to_std(), Err(OutOfRangeError(())));
1147 assert_eq!(TimeDelta::milliseconds(-1).to_std(), Err(OutOfRangeError(())));
1148 }
1149
1150 #[test]
test_from_std()1151 fn test_from_std() {
1152 assert_eq!(Ok(TimeDelta::seconds(1)), TimeDelta::from_std(Duration::new(1, 0)));
1153 assert_eq!(Ok(TimeDelta::seconds(86_401)), TimeDelta::from_std(Duration::new(86_401, 0)));
1154 assert_eq!(
1155 Ok(TimeDelta::milliseconds(123)),
1156 TimeDelta::from_std(Duration::new(0, 123_000_000))
1157 );
1158 assert_eq!(
1159 Ok(TimeDelta::milliseconds(123_765)),
1160 TimeDelta::from_std(Duration::new(123, 765_000_000))
1161 );
1162 assert_eq!(Ok(TimeDelta::nanoseconds(777)), TimeDelta::from_std(Duration::new(0, 777)));
1163 assert_eq!(Ok(MAX), TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_000)));
1164 assert_eq!(
1165 TimeDelta::from_std(Duration::new(9_223_372_036_854_776, 0)),
1166 Err(OutOfRangeError(()))
1167 );
1168 assert_eq!(
1169 TimeDelta::from_std(Duration::new(9_223_372_036_854_775, 807_000_001)),
1170 Err(OutOfRangeError(()))
1171 );
1172 }
1173
1174 #[test]
test_duration_const()1175 fn test_duration_const() {
1176 const ONE_WEEK: TimeDelta = TimeDelta::weeks(1);
1177 const ONE_DAY: TimeDelta = TimeDelta::days(1);
1178 const ONE_HOUR: TimeDelta = TimeDelta::hours(1);
1179 const ONE_MINUTE: TimeDelta = TimeDelta::minutes(1);
1180 const ONE_SECOND: TimeDelta = TimeDelta::seconds(1);
1181 const ONE_MILLI: TimeDelta = TimeDelta::milliseconds(1);
1182 const ONE_MICRO: TimeDelta = TimeDelta::microseconds(1);
1183 const ONE_NANO: TimeDelta = TimeDelta::nanoseconds(1);
1184 let combo: TimeDelta = ONE_WEEK
1185 + ONE_DAY
1186 + ONE_HOUR
1187 + ONE_MINUTE
1188 + ONE_SECOND
1189 + ONE_MILLI
1190 + ONE_MICRO
1191 + ONE_NANO;
1192
1193 assert!(ONE_WEEK != TimeDelta::zero());
1194 assert!(ONE_DAY != TimeDelta::zero());
1195 assert!(ONE_HOUR != TimeDelta::zero());
1196 assert!(ONE_MINUTE != TimeDelta::zero());
1197 assert!(ONE_SECOND != TimeDelta::zero());
1198 assert!(ONE_MILLI != TimeDelta::zero());
1199 assert!(ONE_MICRO != TimeDelta::zero());
1200 assert!(ONE_NANO != TimeDelta::zero());
1201 assert_eq!(
1202 combo,
1203 TimeDelta::seconds(86400 * 7 + 86400 + 3600 + 60 + 1)
1204 + TimeDelta::nanoseconds(1 + 1_000 + 1_000_000)
1205 );
1206 }
1207
1208 #[test]
1209 #[cfg(feature = "rkyv-validation")]
test_rkyv_validation()1210 fn test_rkyv_validation() {
1211 let duration = TimeDelta::seconds(1);
1212 let bytes = rkyv::to_bytes::<_, 16>(&duration).unwrap();
1213 assert_eq!(rkyv::from_bytes::<TimeDelta>(&bytes).unwrap(), duration);
1214 }
1215 }
1216