1//! The [`Duration`] struct and its associated `impl`s.
2
3use core::cmp::Ordering;
4use core::fmt;
5use core::iter::Sum;
6use core::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
7use core::time::Duration as StdDuration;
8
9use crate::convert::*;
10use crate::error;
11#[cfg(feature = "std")]
12use crate::Instant;
13
14/// By explicitly inserting this enum where padding is expected, the compiler is able to better
15/// perform niche value optimization.
16#[repr(u32)]
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
18pub(crate) enum Padding {
19 #[allow(clippy::missing_docs_in_private_items)]
20 Optimize,
21}
22
23impl Default for Padding {
24 fn default() -> Self {
25 Self::Optimize
26 }
27}
28
29/// A span of time with nanosecond precision.
30///
31/// Each `Duration` is composed of a whole number of seconds and a fractional part represented in
32/// nanoseconds.
33///
34/// This implementation allows for negative durations, unlike [`core::time::Duration`].
35#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
36pub struct Duration {
37 /// Number of whole seconds.
38 seconds: i64,
39 /// Number of nanoseconds within the second. The sign always matches the `seconds` field.
40 nanoseconds: i32, // always -10^9 < nanoseconds < 10^9
41 #[allow(clippy::missing_docs_in_private_items)]
42 padding: Padding,
43}
44
45impl fmt::Debug for Duration {
46 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
47 f&mut DebugStruct<'_, '_>.debug_struct("Duration")
48 .field("seconds", &self.seconds)
49 .field(name:"nanoseconds", &self.nanoseconds)
50 .finish()
51 }
52}
53
54/// This is adapted from the `std` implementation, which uses mostly bit
55/// operations to ensure the highest precision:
56/// https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340
57/// Changes from `std` are marked and explained below.
58#[rustfmt::skip] // Skip `rustfmt` because it reformats the arguments of the macro weirdly.
59macro_rules! try_from_secs {
60 (
61 secs = $secs: expr,
62 mantissa_bits = $mant_bits: literal,
63 exponent_bits = $exp_bits: literal,
64 offset = $offset: literal,
65 bits_ty = $bits_ty:ty,
66 bits_ty_signed = $bits_ty_signed:ty,
67 double_ty = $double_ty:ty,
68 float_ty = $float_ty:ty,
69 is_nan = $is_nan:expr,
70 is_overflow = $is_overflow:expr,
71 ) => {{
72 'value: {
73 const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2;
74 const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1;
75 const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1;
76
77 // Change from std: No error check for negative values necessary.
78
79 let bits = $secs.to_bits();
80 let mant = (bits & MANT_MASK) | (MANT_MASK + 1);
81 let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP;
82
83 let (secs, nanos) = if exp < -31 {
84 // the input represents less than 1ns and can not be rounded to it
85 (0u64, 0u32)
86 } else if exp < 0 {
87 // the input is less than 1 second
88 let t = <$double_ty>::from(mant) << ($offset + exp);
89 let nanos_offset = $mant_bits + $offset;
90 let nanos_tmp = u128::from(Nanosecond.per(Second)) * u128::from(t);
91 let nanos = (nanos_tmp >> nanos_offset) as u32;
92
93 let rem_mask = (1 << nanos_offset) - 1;
94 let rem_msb_mask = 1 << (nanos_offset - 1);
95 let rem = nanos_tmp & rem_mask;
96 let is_tie = rem == rem_msb_mask;
97 let is_even = (nanos & 1) == 0;
98 let rem_msb = nanos_tmp & rem_msb_mask == 0;
99 let add_ns = !(rem_msb || (is_even && is_tie));
100
101 // f32 does not have enough precision to trigger the second branch
102 // since it can not represent numbers between 0.999_999_940_395 and 1.0.
103 let nanos = nanos + add_ns as u32;
104 if ($mant_bits == 23) || (nanos != Nanosecond.per(Second)) {
105 (0, nanos)
106 } else {
107 (1, 0)
108 }
109 } else if exp < $mant_bits {
110 let secs = u64::from(mant >> ($mant_bits - exp));
111 let t = <$double_ty>::from((mant << exp) & MANT_MASK);
112 let nanos_offset = $mant_bits;
113 let nanos_tmp = <$double_ty>::from(Nanosecond.per(Second)) * t;
114 let nanos = (nanos_tmp >> nanos_offset) as u32;
115
116 let rem_mask = (1 << nanos_offset) - 1;
117 let rem_msb_mask = 1 << (nanos_offset - 1);
118 let rem = nanos_tmp & rem_mask;
119 let is_tie = rem == rem_msb_mask;
120 let is_even = (nanos & 1) == 0;
121 let rem_msb = nanos_tmp & rem_msb_mask == 0;
122 let add_ns = !(rem_msb || (is_even && is_tie));
123
124 // f32 does not have enough precision to trigger the second branch.
125 // For example, it can not represent numbers between 1.999_999_880...
126 // and 2.0. Bigger values result in even smaller precision of the
127 // fractional part.
128 let nanos = nanos + add_ns as u32;
129 if ($mant_bits == 23) || (nanos != Nanosecond.per(Second)) {
130 (secs, nanos)
131 } else {
132 (secs + 1, 0)
133 }
134 } else if exp < 63 {
135 // Change from std: The exponent here is 63 instead of 64,
136 // because i64::MAX + 1 is 2^63.
137
138 // the input has no fractional part
139 let secs = u64::from(mant) << (exp - $mant_bits);
140 (secs, 0)
141 } else if bits == (i64::MIN as $float_ty).to_bits() {
142 // Change from std: Signed integers are asymmetrical in that
143 // iN::MIN is -iN::MAX - 1. So for example i8 covers the
144 // following numbers -128..=127. The check above (exp < 63)
145 // doesn't cover i64::MIN as that is -2^63, so we have this
146 // additional case to handle the asymmetry of iN::MIN.
147 break 'value Self::new_unchecked(i64::MIN, 0);
148 } else if $secs.is_nan() {
149 // Change from std: std doesn't differentiate between the error
150 // cases.
151 $is_nan
152 } else {
153 $is_overflow
154 };
155
156 // Change from std: All the code is mostly unmodified in that it
157 // simply calculates an unsigned integer. Here we extract the sign
158 // bit and assign it to the number. We basically manually do two's
159 // complement here, we could also use an if and just negate the
160 // numbers based on the sign, but it turns out to be quite a bit
161 // slower.
162 let mask = (bits as $bits_ty_signed) >> ($mant_bits + $exp_bits);
163 #[allow(trivial_numeric_casts)]
164 let secs_signed = ((secs as i64) ^ (mask as i64)) - (mask as i64);
165 #[allow(trivial_numeric_casts)]
166 let nanos_signed = ((nanos as i32) ^ (mask as i32)) - (mask as i32);
167 Self::new_unchecked(secs_signed, nanos_signed)
168 }
169 }};
170}
171
172impl Duration {
173 // region: constants
174 /// Equivalent to `0.seconds()`.
175 ///
176 /// ```rust
177 /// # use time::{Duration, ext::NumericalDuration};
178 /// assert_eq!(Duration::ZERO, 0.seconds());
179 /// ```
180 pub const ZERO: Self = Self::seconds(0);
181
182 /// Equivalent to `1.nanoseconds()`.
183 ///
184 /// ```rust
185 /// # use time::{Duration, ext::NumericalDuration};
186 /// assert_eq!(Duration::NANOSECOND, 1.nanoseconds());
187 /// ```
188 pub const NANOSECOND: Self = Self::nanoseconds(1);
189
190 /// Equivalent to `1.microseconds()`.
191 ///
192 /// ```rust
193 /// # use time::{Duration, ext::NumericalDuration};
194 /// assert_eq!(Duration::MICROSECOND, 1.microseconds());
195 /// ```
196 pub const MICROSECOND: Self = Self::microseconds(1);
197
198 /// Equivalent to `1.milliseconds()`.
199 ///
200 /// ```rust
201 /// # use time::{Duration, ext::NumericalDuration};
202 /// assert_eq!(Duration::MILLISECOND, 1.milliseconds());
203 /// ```
204 pub const MILLISECOND: Self = Self::milliseconds(1);
205
206 /// Equivalent to `1.seconds()`.
207 ///
208 /// ```rust
209 /// # use time::{Duration, ext::NumericalDuration};
210 /// assert_eq!(Duration::SECOND, 1.seconds());
211 /// ```
212 pub const SECOND: Self = Self::seconds(1);
213
214 /// Equivalent to `1.minutes()`.
215 ///
216 /// ```rust
217 /// # use time::{Duration, ext::NumericalDuration};
218 /// assert_eq!(Duration::MINUTE, 1.minutes());
219 /// ```
220 pub const MINUTE: Self = Self::minutes(1);
221
222 /// Equivalent to `1.hours()`.
223 ///
224 /// ```rust
225 /// # use time::{Duration, ext::NumericalDuration};
226 /// assert_eq!(Duration::HOUR, 1.hours());
227 /// ```
228 pub const HOUR: Self = Self::hours(1);
229
230 /// Equivalent to `1.days()`.
231 ///
232 /// ```rust
233 /// # use time::{Duration, ext::NumericalDuration};
234 /// assert_eq!(Duration::DAY, 1.days());
235 /// ```
236 pub const DAY: Self = Self::days(1);
237
238 /// Equivalent to `1.weeks()`.
239 ///
240 /// ```rust
241 /// # use time::{Duration, ext::NumericalDuration};
242 /// assert_eq!(Duration::WEEK, 1.weeks());
243 /// ```
244 pub const WEEK: Self = Self::weeks(1);
245
246 /// The minimum possible duration. Adding any negative duration to this will cause an overflow.
247 pub const MIN: Self = Self::new_unchecked(i64::MIN, -((Nanosecond.per(Second) - 1) as i32));
248
249 /// The maximum possible duration. Adding any positive duration to this will cause an overflow.
250 pub const MAX: Self = Self::new_unchecked(i64::MAX, (Nanosecond.per(Second) - 1) as _);
251 // endregion constants
252
253 // region: is_{sign}
254 /// Check if a duration is exactly zero.
255 ///
256 /// ```rust
257 /// # use time::ext::NumericalDuration;
258 /// assert!(0.seconds().is_zero());
259 /// assert!(!1.nanoseconds().is_zero());
260 /// ```
261 pub const fn is_zero(self) -> bool {
262 self.seconds == 0 && self.nanoseconds == 0
263 }
264
265 /// Check if a duration is negative.
266 ///
267 /// ```rust
268 /// # use time::ext::NumericalDuration;
269 /// assert!((-1).seconds().is_negative());
270 /// assert!(!0.seconds().is_negative());
271 /// assert!(!1.seconds().is_negative());
272 /// ```
273 pub const fn is_negative(self) -> bool {
274 self.seconds < 0 || self.nanoseconds < 0
275 }
276
277 /// Check if a duration is positive.
278 ///
279 /// ```rust
280 /// # use time::ext::NumericalDuration;
281 /// assert!(1.seconds().is_positive());
282 /// assert!(!0.seconds().is_positive());
283 /// assert!(!(-1).seconds().is_positive());
284 /// ```
285 pub const fn is_positive(self) -> bool {
286 self.seconds > 0 || self.nanoseconds > 0
287 }
288 // endregion is_{sign}
289
290 // region: abs
291 /// Get the absolute value of the duration.
292 ///
293 /// This method saturates the returned value if it would otherwise overflow.
294 ///
295 /// ```rust
296 /// # use time::ext::NumericalDuration;
297 /// assert_eq!(1.seconds().abs(), 1.seconds());
298 /// assert_eq!(0.seconds().abs(), 0.seconds());
299 /// assert_eq!((-1).seconds().abs(), 1.seconds());
300 /// ```
301 pub const fn abs(self) -> Self {
302 Self::new_unchecked(self.seconds.saturating_abs(), self.nanoseconds.abs())
303 }
304
305 /// Convert the existing `Duration` to a `std::time::Duration` and its sign. This returns a
306 /// [`std::time::Duration`] and does not saturate the returned value (unlike [`Duration::abs`]).
307 ///
308 /// ```rust
309 /// # use time::ext::{NumericalDuration, NumericalStdDuration};
310 /// assert_eq!(1.seconds().unsigned_abs(), 1.std_seconds());
311 /// assert_eq!(0.seconds().unsigned_abs(), 0.std_seconds());
312 /// assert_eq!((-1).seconds().unsigned_abs(), 1.std_seconds());
313 /// ```
314 pub const fn unsigned_abs(self) -> StdDuration {
315 StdDuration::new(self.seconds.unsigned_abs(), self.nanoseconds.unsigned_abs())
316 }
317 // endregion abs
318
319 // region: constructors
320 /// Create a new `Duration` without checking the validity of the components.
321 pub(crate) const fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
322 if seconds < 0 {
323 debug_assert!(nanoseconds <= 0);
324 debug_assert!(nanoseconds > -(Nanosecond.per(Second) as i32));
325 } else if seconds > 0 {
326 debug_assert!(nanoseconds >= 0);
327 debug_assert!(nanoseconds < Nanosecond.per(Second) as _);
328 } else {
329 debug_assert!(nanoseconds.unsigned_abs() < Nanosecond.per(Second));
330 }
331
332 Self {
333 seconds,
334 nanoseconds,
335 padding: Padding::Optimize,
336 }
337 }
338
339 /// Create a new `Duration` with the provided seconds and nanoseconds. If nanoseconds is at
340 /// least ±10<sup>9</sup>, it will wrap to the number of seconds.
341 ///
342 /// ```rust
343 /// # use time::{Duration, ext::NumericalDuration};
344 /// assert_eq!(Duration::new(1, 0), 1.seconds());
345 /// assert_eq!(Duration::new(-1, 0), (-1).seconds());
346 /// assert_eq!(Duration::new(1, 2_000_000_000), 3.seconds());
347 /// ```
348 pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self {
349 seconds = expect_opt!(
350 seconds.checked_add(nanoseconds as i64 / Nanosecond.per(Second) as i64),
351 "overflow constructing `time::Duration`"
352 );
353 nanoseconds %= Nanosecond.per(Second) as i32;
354
355 if seconds > 0 && nanoseconds < 0 {
356 // `seconds` cannot overflow here because it is positive.
357 seconds -= 1;
358 nanoseconds += Nanosecond.per(Second) as i32;
359 } else if seconds < 0 && nanoseconds > 0 {
360 // `seconds` cannot overflow here because it is negative.
361 seconds += 1;
362 nanoseconds -= Nanosecond.per(Second) as i32;
363 }
364
365 Self::new_unchecked(seconds, nanoseconds)
366 }
367
368 /// Create a new `Duration` with the given number of weeks. Equivalent to
369 /// `Duration::seconds(weeks * 604_800)`.
370 ///
371 /// ```rust
372 /// # use time::{Duration, ext::NumericalDuration};
373 /// assert_eq!(Duration::weeks(1), 604_800.seconds());
374 /// ```
375 pub const fn weeks(weeks: i64) -> Self {
376 Self::seconds(expect_opt!(
377 weeks.checked_mul(Second.per(Week) as _),
378 "overflow constructing `time::Duration`"
379 ))
380 }
381
382 /// Create a new `Duration` with the given number of days. Equivalent to
383 /// `Duration::seconds(days * 86_400)`.
384 ///
385 /// ```rust
386 /// # use time::{Duration, ext::NumericalDuration};
387 /// assert_eq!(Duration::days(1), 86_400.seconds());
388 /// ```
389 pub const fn days(days: i64) -> Self {
390 Self::seconds(expect_opt!(
391 days.checked_mul(Second.per(Day) as _),
392 "overflow constructing `time::Duration`"
393 ))
394 }
395
396 /// Create a new `Duration` with the given number of hours. Equivalent to
397 /// `Duration::seconds(hours * 3_600)`.
398 ///
399 /// ```rust
400 /// # use time::{Duration, ext::NumericalDuration};
401 /// assert_eq!(Duration::hours(1), 3_600.seconds());
402 /// ```
403 pub const fn hours(hours: i64) -> Self {
404 Self::seconds(expect_opt!(
405 hours.checked_mul(Second.per(Hour) as _),
406 "overflow constructing `time::Duration`"
407 ))
408 }
409
410 /// Create a new `Duration` with the given number of minutes. Equivalent to
411 /// `Duration::seconds(minutes * 60)`.
412 ///
413 /// ```rust
414 /// # use time::{Duration, ext::NumericalDuration};
415 /// assert_eq!(Duration::minutes(1), 60.seconds());
416 /// ```
417 pub const fn minutes(minutes: i64) -> Self {
418 Self::seconds(expect_opt!(
419 minutes.checked_mul(Second.per(Minute) as _),
420 "overflow constructing `time::Duration`"
421 ))
422 }
423
424 /// Create a new `Duration` with the given number of seconds.
425 ///
426 /// ```rust
427 /// # use time::{Duration, ext::NumericalDuration};
428 /// assert_eq!(Duration::seconds(1), 1_000.milliseconds());
429 /// ```
430 pub const fn seconds(seconds: i64) -> Self {
431 Self::new_unchecked(seconds, 0)
432 }
433
434 /// Creates a new `Duration` from the specified number of seconds represented as `f64`.
435 ///
436 /// ```rust
437 /// # use time::{Duration, ext::NumericalDuration};
438 /// assert_eq!(Duration::seconds_f64(0.5), 0.5.seconds());
439 /// assert_eq!(Duration::seconds_f64(-0.5), -0.5.seconds());
440 /// ```
441 pub fn seconds_f64(seconds: f64) -> Self {
442 try_from_secs!(
443 secs = seconds,
444 mantissa_bits = 52,
445 exponent_bits = 11,
446 offset = 44,
447 bits_ty = u64,
448 bits_ty_signed = i64,
449 double_ty = u128,
450 float_ty = f64,
451 is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f64`"),
452 is_overflow = crate::expect_failed("overflow constructing `time::Duration`"),
453 )
454 }
455
456 /// Creates a new `Duration` from the specified number of seconds represented as `f32`.
457 ///
458 /// ```rust
459 /// # use time::{Duration, ext::NumericalDuration};
460 /// assert_eq!(Duration::seconds_f32(0.5), 0.5.seconds());
461 /// assert_eq!(Duration::seconds_f32(-0.5), (-0.5).seconds());
462 /// ```
463 pub fn seconds_f32(seconds: f32) -> Self {
464 try_from_secs!(
465 secs = seconds,
466 mantissa_bits = 23,
467 exponent_bits = 8,
468 offset = 41,
469 bits_ty = u32,
470 bits_ty_signed = i32,
471 double_ty = u64,
472 float_ty = f32,
473 is_nan = crate::expect_failed("passed NaN to `time::Duration::seconds_f32`"),
474 is_overflow = crate::expect_failed("overflow constructing `time::Duration`"),
475 )
476 }
477
478 /// Creates a new `Duration` from the specified number of seconds
479 /// represented as `f64`. Any values that are out of bounds are saturated at
480 /// the minimum or maximum respectively. `NaN` gets turned into a `Duration`
481 /// of 0 seconds.
482 ///
483 /// ```rust
484 /// # use time::{Duration, ext::NumericalDuration};
485 /// assert_eq!(Duration::saturating_seconds_f64(0.5), 0.5.seconds());
486 /// assert_eq!(Duration::saturating_seconds_f64(-0.5), -0.5.seconds());
487 /// assert_eq!(
488 /// Duration::saturating_seconds_f64(f64::NAN),
489 /// Duration::new(0, 0),
490 /// );
491 /// assert_eq!(
492 /// Duration::saturating_seconds_f64(f64::NEG_INFINITY),
493 /// Duration::MIN,
494 /// );
495 /// assert_eq!(
496 /// Duration::saturating_seconds_f64(f64::INFINITY),
497 /// Duration::MAX,
498 /// );
499 /// ```
500 pub fn saturating_seconds_f64(seconds: f64) -> Self {
501 try_from_secs!(
502 secs = seconds,
503 mantissa_bits = 52,
504 exponent_bits = 11,
505 offset = 44,
506 bits_ty = u64,
507 bits_ty_signed = i64,
508 double_ty = u128,
509 float_ty = f64,
510 is_nan = return Self::ZERO,
511 is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX },
512 )
513 }
514
515 /// Creates a new `Duration` from the specified number of seconds
516 /// represented as `f32`. Any values that are out of bounds are saturated at
517 /// the minimum or maximum respectively. `NaN` gets turned into a `Duration`
518 /// of 0 seconds.
519 ///
520 /// ```rust
521 /// # use time::{Duration, ext::NumericalDuration};
522 /// assert_eq!(Duration::saturating_seconds_f32(0.5), 0.5.seconds());
523 /// assert_eq!(Duration::saturating_seconds_f32(-0.5), (-0.5).seconds());
524 /// assert_eq!(
525 /// Duration::saturating_seconds_f32(f32::NAN),
526 /// Duration::new(0, 0),
527 /// );
528 /// assert_eq!(
529 /// Duration::saturating_seconds_f32(f32::NEG_INFINITY),
530 /// Duration::MIN,
531 /// );
532 /// assert_eq!(
533 /// Duration::saturating_seconds_f32(f32::INFINITY),
534 /// Duration::MAX,
535 /// );
536 /// ```
537 pub fn saturating_seconds_f32(seconds: f32) -> Self {
538 try_from_secs!(
539 secs = seconds,
540 mantissa_bits = 23,
541 exponent_bits = 8,
542 offset = 41,
543 bits_ty = u32,
544 bits_ty_signed = i32,
545 double_ty = u64,
546 float_ty = f32,
547 is_nan = return Self::ZERO,
548 is_overflow = return if seconds < 0.0 { Self::MIN } else { Self::MAX },
549 )
550 }
551
552 /// Creates a new `Duration` from the specified number of seconds
553 /// represented as `f64`. Returns `None` if the `Duration` can't be
554 /// represented.
555 ///
556 /// ```rust
557 /// # use time::{Duration, ext::NumericalDuration};
558 /// assert_eq!(Duration::checked_seconds_f64(0.5), Some(0.5.seconds()));
559 /// assert_eq!(Duration::checked_seconds_f64(-0.5), Some(-0.5.seconds()));
560 /// assert_eq!(Duration::checked_seconds_f64(f64::NAN), None);
561 /// assert_eq!(Duration::checked_seconds_f64(f64::NEG_INFINITY), None);
562 /// assert_eq!(Duration::checked_seconds_f64(f64::INFINITY), None);
563 /// ```
564 pub fn checked_seconds_f64(seconds: f64) -> Option<Self> {
565 Some(try_from_secs!(
566 secs = seconds,
567 mantissa_bits = 52,
568 exponent_bits = 11,
569 offset = 44,
570 bits_ty = u64,
571 bits_ty_signed = i64,
572 double_ty = u128,
573 float_ty = f64,
574 is_nan = return None,
575 is_overflow = return None,
576 ))
577 }
578
579 /// Creates a new `Duration` from the specified number of seconds
580 /// represented as `f32`. Returns `None` if the `Duration` can't be
581 /// represented.
582 ///
583 /// ```rust
584 /// # use time::{Duration, ext::NumericalDuration};
585 /// assert_eq!(Duration::checked_seconds_f32(0.5), Some(0.5.seconds()));
586 /// assert_eq!(Duration::checked_seconds_f32(-0.5), Some(-0.5.seconds()));
587 /// assert_eq!(Duration::checked_seconds_f32(f32::NAN), None);
588 /// assert_eq!(Duration::checked_seconds_f32(f32::NEG_INFINITY), None);
589 /// assert_eq!(Duration::checked_seconds_f32(f32::INFINITY), None);
590 /// ```
591 pub fn checked_seconds_f32(seconds: f32) -> Option<Self> {
592 Some(try_from_secs!(
593 secs = seconds,
594 mantissa_bits = 23,
595 exponent_bits = 8,
596 offset = 41,
597 bits_ty = u32,
598 bits_ty_signed = i32,
599 double_ty = u64,
600 float_ty = f32,
601 is_nan = return None,
602 is_overflow = return None,
603 ))
604 }
605
606 /// Create a new `Duration` with the given number of milliseconds.
607 ///
608 /// ```rust
609 /// # use time::{Duration, ext::NumericalDuration};
610 /// assert_eq!(Duration::milliseconds(1), 1_000.microseconds());
611 /// assert_eq!(Duration::milliseconds(-1), (-1_000).microseconds());
612 /// ```
613 pub const fn milliseconds(milliseconds: i64) -> Self {
614 Self::new_unchecked(
615 milliseconds / Millisecond.per(Second) as i64,
616 (milliseconds % Millisecond.per(Second) as i64 * Nanosecond.per(Millisecond) as i64)
617 as _,
618 )
619 }
620
621 /// Create a new `Duration` with the given number of microseconds.
622 ///
623 /// ```rust
624 /// # use time::{Duration, ext::NumericalDuration};
625 /// assert_eq!(Duration::microseconds(1), 1_000.nanoseconds());
626 /// assert_eq!(Duration::microseconds(-1), (-1_000).nanoseconds());
627 /// ```
628 pub const fn microseconds(microseconds: i64) -> Self {
629 Self::new_unchecked(
630 microseconds / Microsecond.per(Second) as i64,
631 (microseconds % Microsecond.per(Second) as i64 * Nanosecond.per(Microsecond) as i64)
632 as _,
633 )
634 }
635
636 /// Create a new `Duration` with the given number of nanoseconds.
637 ///
638 /// ```rust
639 /// # use time::{Duration, ext::NumericalDuration};
640 /// assert_eq!(Duration::nanoseconds(1), 1.microseconds() / 1_000);
641 /// assert_eq!(Duration::nanoseconds(-1), (-1).microseconds() / 1_000);
642 /// ```
643 pub const fn nanoseconds(nanoseconds: i64) -> Self {
644 Self::new_unchecked(
645 nanoseconds / Nanosecond.per(Second) as i64,
646 (nanoseconds % Nanosecond.per(Second) as i64) as _,
647 )
648 }
649
650 /// Create a new `Duration` with the given number of nanoseconds.
651 ///
652 /// As the input range cannot be fully mapped to the output, this should only be used where it's
653 /// known to result in a valid value.
654 pub(crate) const fn nanoseconds_i128(nanoseconds: i128) -> Self {
655 let seconds = nanoseconds / Nanosecond.per(Second) as i128;
656 let nanoseconds = nanoseconds % Nanosecond.per(Second) as i128;
657
658 if seconds > i64::MAX as i128 || seconds < i64::MIN as i128 {
659 crate::expect_failed("overflow constructing `time::Duration`");
660 }
661
662 Self::new_unchecked(seconds as _, nanoseconds as _)
663 }
664 // endregion constructors
665
666 // region: getters
667 /// Get the number of whole weeks in the duration.
668 ///
669 /// ```rust
670 /// # use time::ext::NumericalDuration;
671 /// assert_eq!(1.weeks().whole_weeks(), 1);
672 /// assert_eq!((-1).weeks().whole_weeks(), -1);
673 /// assert_eq!(6.days().whole_weeks(), 0);
674 /// assert_eq!((-6).days().whole_weeks(), 0);
675 /// ```
676 pub const fn whole_weeks(self) -> i64 {
677 self.whole_seconds() / Second.per(Week) as i64
678 }
679
680 /// Get the number of whole days in the duration.
681 ///
682 /// ```rust
683 /// # use time::ext::NumericalDuration;
684 /// assert_eq!(1.days().whole_days(), 1);
685 /// assert_eq!((-1).days().whole_days(), -1);
686 /// assert_eq!(23.hours().whole_days(), 0);
687 /// assert_eq!((-23).hours().whole_days(), 0);
688 /// ```
689 pub const fn whole_days(self) -> i64 {
690 self.whole_seconds() / Second.per(Day) as i64
691 }
692
693 /// Get the number of whole hours in the duration.
694 ///
695 /// ```rust
696 /// # use time::ext::NumericalDuration;
697 /// assert_eq!(1.hours().whole_hours(), 1);
698 /// assert_eq!((-1).hours().whole_hours(), -1);
699 /// assert_eq!(59.minutes().whole_hours(), 0);
700 /// assert_eq!((-59).minutes().whole_hours(), 0);
701 /// ```
702 pub const fn whole_hours(self) -> i64 {
703 self.whole_seconds() / Second.per(Hour) as i64
704 }
705
706 /// Get the number of whole minutes in the duration.
707 ///
708 /// ```rust
709 /// # use time::ext::NumericalDuration;
710 /// assert_eq!(1.minutes().whole_minutes(), 1);
711 /// assert_eq!((-1).minutes().whole_minutes(), -1);
712 /// assert_eq!(59.seconds().whole_minutes(), 0);
713 /// assert_eq!((-59).seconds().whole_minutes(), 0);
714 /// ```
715 pub const fn whole_minutes(self) -> i64 {
716 self.whole_seconds() / Second.per(Minute) as i64
717 }
718
719 /// Get the number of whole seconds in the duration.
720 ///
721 /// ```rust
722 /// # use time::ext::NumericalDuration;
723 /// assert_eq!(1.seconds().whole_seconds(), 1);
724 /// assert_eq!((-1).seconds().whole_seconds(), -1);
725 /// assert_eq!(1.minutes().whole_seconds(), 60);
726 /// assert_eq!((-1).minutes().whole_seconds(), -60);
727 /// ```
728 pub const fn whole_seconds(self) -> i64 {
729 self.seconds
730 }
731
732 /// Get the number of fractional seconds in the duration.
733 ///
734 /// ```rust
735 /// # use time::ext::NumericalDuration;
736 /// assert_eq!(1.5.seconds().as_seconds_f64(), 1.5);
737 /// assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5);
738 /// ```
739 pub fn as_seconds_f64(self) -> f64 {
740 self.seconds as f64 + self.nanoseconds as f64 / Nanosecond.per(Second) as f64
741 }
742
743 /// Get the number of fractional seconds in the duration.
744 ///
745 /// ```rust
746 /// # use time::ext::NumericalDuration;
747 /// assert_eq!(1.5.seconds().as_seconds_f32(), 1.5);
748 /// assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5);
749 /// ```
750 pub fn as_seconds_f32(self) -> f32 {
751 self.seconds as f32 + self.nanoseconds as f32 / Nanosecond.per(Second) as f32
752 }
753
754 /// Get the number of whole milliseconds in the duration.
755 ///
756 /// ```rust
757 /// # use time::ext::NumericalDuration;
758 /// assert_eq!(1.seconds().whole_milliseconds(), 1_000);
759 /// assert_eq!((-1).seconds().whole_milliseconds(), -1_000);
760 /// assert_eq!(1.milliseconds().whole_milliseconds(), 1);
761 /// assert_eq!((-1).milliseconds().whole_milliseconds(), -1);
762 /// ```
763 pub const fn whole_milliseconds(self) -> i128 {
764 self.seconds as i128 * Millisecond.per(Second) as i128
765 + self.nanoseconds as i128 / Nanosecond.per(Millisecond) as i128
766 }
767
768 /// Get the number of milliseconds past the number of whole seconds.
769 ///
770 /// Always in the range `-1_000..1_000`.
771 ///
772 /// ```rust
773 /// # use time::ext::NumericalDuration;
774 /// assert_eq!(1.4.seconds().subsec_milliseconds(), 400);
775 /// assert_eq!((-1.4).seconds().subsec_milliseconds(), -400);
776 /// ```
777 // Allow the lint, as the value is guaranteed to be less than 1000.
778 pub const fn subsec_milliseconds(self) -> i16 {
779 (self.nanoseconds / Nanosecond.per(Millisecond) as i32) as _
780 }
781
782 /// Get the number of whole microseconds in the duration.
783 ///
784 /// ```rust
785 /// # use time::ext::NumericalDuration;
786 /// assert_eq!(1.milliseconds().whole_microseconds(), 1_000);
787 /// assert_eq!((-1).milliseconds().whole_microseconds(), -1_000);
788 /// assert_eq!(1.microseconds().whole_microseconds(), 1);
789 /// assert_eq!((-1).microseconds().whole_microseconds(), -1);
790 /// ```
791 pub const fn whole_microseconds(self) -> i128 {
792 self.seconds as i128 * Microsecond.per(Second) as i128
793 + self.nanoseconds as i128 / Nanosecond.per(Microsecond) as i128
794 }
795
796 /// Get the number of microseconds past the number of whole seconds.
797 ///
798 /// Always in the range `-1_000_000..1_000_000`.
799 ///
800 /// ```rust
801 /// # use time::ext::NumericalDuration;
802 /// assert_eq!(1.0004.seconds().subsec_microseconds(), 400);
803 /// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400);
804 /// ```
805 pub const fn subsec_microseconds(self) -> i32 {
806 self.nanoseconds / Nanosecond.per(Microsecond) as i32
807 }
808
809 /// Get the number of nanoseconds in the duration.
810 ///
811 /// ```rust
812 /// # use time::ext::NumericalDuration;
813 /// assert_eq!(1.microseconds().whole_nanoseconds(), 1_000);
814 /// assert_eq!((-1).microseconds().whole_nanoseconds(), -1_000);
815 /// assert_eq!(1.nanoseconds().whole_nanoseconds(), 1);
816 /// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1);
817 /// ```
818 pub const fn whole_nanoseconds(self) -> i128 {
819 self.seconds as i128 * Nanosecond.per(Second) as i128 + self.nanoseconds as i128
820 }
821
822 /// Get the number of nanoseconds past the number of whole seconds.
823 ///
824 /// The returned value will always be in the range `-1_000_000_000..1_000_000_000`.
825 ///
826 /// ```rust
827 /// # use time::ext::NumericalDuration;
828 /// assert_eq!(1.000_000_400.seconds().subsec_nanoseconds(), 400);
829 /// assert_eq!((-1.000_000_400).seconds().subsec_nanoseconds(), -400);
830 /// ```
831 pub const fn subsec_nanoseconds(self) -> i32 {
832 self.nanoseconds
833 }
834 // endregion getters
835
836 // region: checked arithmetic
837 /// Computes `self + rhs`, returning `None` if an overflow occurred.
838 ///
839 /// ```rust
840 /// # use time::{Duration, ext::NumericalDuration};
841 /// assert_eq!(5.seconds().checked_add(5.seconds()), Some(10.seconds()));
842 /// assert_eq!(Duration::MAX.checked_add(1.nanoseconds()), None);
843 /// assert_eq!((-5).seconds().checked_add(5.seconds()), Some(0.seconds()));
844 /// ```
845 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
846 let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds));
847 let mut nanoseconds = self.nanoseconds + rhs.nanoseconds;
848
849 if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
850 nanoseconds -= Nanosecond.per(Second) as i32;
851 seconds = const_try_opt!(seconds.checked_add(1));
852 } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
853 {
854 nanoseconds += Nanosecond.per(Second) as i32;
855 seconds = const_try_opt!(seconds.checked_sub(1));
856 }
857
858 Some(Self::new_unchecked(seconds, nanoseconds))
859 }
860
861 /// Computes `self - rhs`, returning `None` if an overflow occurred.
862 ///
863 /// ```rust
864 /// # use time::{Duration, ext::NumericalDuration};
865 /// assert_eq!(5.seconds().checked_sub(5.seconds()), Some(Duration::ZERO));
866 /// assert_eq!(Duration::MIN.checked_sub(1.nanoseconds()), None);
867 /// assert_eq!(5.seconds().checked_sub(10.seconds()), Some((-5).seconds()));
868 /// ```
869 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
870 let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds));
871 let mut nanoseconds = self.nanoseconds - rhs.nanoseconds;
872
873 if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
874 nanoseconds -= Nanosecond.per(Second) as i32;
875 seconds = const_try_opt!(seconds.checked_add(1));
876 } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
877 {
878 nanoseconds += Nanosecond.per(Second) as i32;
879 seconds = const_try_opt!(seconds.checked_sub(1));
880 }
881
882 Some(Self::new_unchecked(seconds, nanoseconds))
883 }
884
885 /// Computes `self * rhs`, returning `None` if an overflow occurred.
886 ///
887 /// ```rust
888 /// # use time::{Duration, ext::NumericalDuration};
889 /// assert_eq!(5.seconds().checked_mul(2), Some(10.seconds()));
890 /// assert_eq!(5.seconds().checked_mul(-2), Some((-10).seconds()));
891 /// assert_eq!(5.seconds().checked_mul(0), Some(0.seconds()));
892 /// assert_eq!(Duration::MAX.checked_mul(2), None);
893 /// assert_eq!(Duration::MIN.checked_mul(2), None);
894 /// ```
895 pub const fn checked_mul(self, rhs: i32) -> Option<Self> {
896 // Multiply nanoseconds as i64, because it cannot overflow that way.
897 let total_nanos = self.nanoseconds as i64 * rhs as i64;
898 let extra_secs = total_nanos / Nanosecond.per(Second) as i64;
899 let nanoseconds = (total_nanos % Nanosecond.per(Second) as i64) as _;
900 let seconds = const_try_opt!(
901 const_try_opt!(self.seconds.checked_mul(rhs as _)).checked_add(extra_secs)
902 );
903
904 Some(Self::new_unchecked(seconds, nanoseconds))
905 }
906
907 /// Computes `self / rhs`, returning `None` if `rhs == 0` or if the result would overflow.
908 ///
909 /// ```rust
910 /// # use time::ext::NumericalDuration;
911 /// assert_eq!(10.seconds().checked_div(2), Some(5.seconds()));
912 /// assert_eq!(10.seconds().checked_div(-2), Some((-5).seconds()));
913 /// assert_eq!(1.seconds().checked_div(0), None);
914 /// ```
915 pub const fn checked_div(self, rhs: i32) -> Option<Self> {
916 let seconds = const_try_opt!(self.seconds.checked_div(rhs as i64));
917 let carry = self.seconds - seconds * (rhs as i64);
918 let extra_nanos =
919 const_try_opt!((carry * Nanosecond.per(Second) as i64).checked_div(rhs as i64));
920 let nanoseconds = const_try_opt!(self.nanoseconds.checked_div(rhs)) + (extra_nanos as i32);
921
922 Some(Self::new_unchecked(seconds, nanoseconds))
923 }
924 // endregion checked arithmetic
925
926 // region: saturating arithmetic
927 /// Computes `self + rhs`, saturating if an overflow occurred.
928 ///
929 /// ```rust
930 /// # use time::{Duration, ext::NumericalDuration};
931 /// assert_eq!(5.seconds().saturating_add(5.seconds()), 10.seconds());
932 /// assert_eq!(Duration::MAX.saturating_add(1.nanoseconds()), Duration::MAX);
933 /// assert_eq!(
934 /// Duration::MIN.saturating_add((-1).nanoseconds()),
935 /// Duration::MIN
936 /// );
937 /// assert_eq!((-5).seconds().saturating_add(5.seconds()), Duration::ZERO);
938 /// ```
939 pub const fn saturating_add(self, rhs: Self) -> Self {
940 let (mut seconds, overflow) = self.seconds.overflowing_add(rhs.seconds);
941 if overflow {
942 if self.seconds > 0 {
943 return Self::MAX;
944 }
945 return Self::MIN;
946 }
947 let mut nanoseconds = self.nanoseconds + rhs.nanoseconds;
948
949 if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
950 nanoseconds -= Nanosecond.per(Second) as i32;
951 seconds = match seconds.checked_add(1) {
952 Some(seconds) => seconds,
953 None => return Self::MAX,
954 };
955 } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
956 {
957 nanoseconds += Nanosecond.per(Second) as i32;
958 seconds = match seconds.checked_sub(1) {
959 Some(seconds) => seconds,
960 None => return Self::MIN,
961 };
962 }
963
964 Self::new_unchecked(seconds, nanoseconds)
965 }
966
967 /// Computes `self - rhs`, saturating if an overflow occurred.
968 ///
969 /// ```rust
970 /// # use time::{Duration, ext::NumericalDuration};
971 /// assert_eq!(5.seconds().saturating_sub(5.seconds()), Duration::ZERO);
972 /// assert_eq!(Duration::MIN.saturating_sub(1.nanoseconds()), Duration::MIN);
973 /// assert_eq!(
974 /// Duration::MAX.saturating_sub((-1).nanoseconds()),
975 /// Duration::MAX
976 /// );
977 /// assert_eq!(5.seconds().saturating_sub(10.seconds()), (-5).seconds());
978 /// ```
979 pub const fn saturating_sub(self, rhs: Self) -> Self {
980 let (mut seconds, overflow) = self.seconds.overflowing_sub(rhs.seconds);
981 if overflow {
982 if self.seconds > 0 {
983 return Self::MAX;
984 }
985 return Self::MIN;
986 }
987 let mut nanoseconds = self.nanoseconds - rhs.nanoseconds;
988
989 if nanoseconds >= Nanosecond.per(Second) as _ || seconds < 0 && nanoseconds > 0 {
990 nanoseconds -= Nanosecond.per(Second) as i32;
991 seconds = match seconds.checked_add(1) {
992 Some(seconds) => seconds,
993 None => return Self::MAX,
994 };
995 } else if nanoseconds <= -(Nanosecond.per(Second) as i32) || seconds > 0 && nanoseconds < 0
996 {
997 nanoseconds += Nanosecond.per(Second) as i32;
998 seconds = match seconds.checked_sub(1) {
999 Some(seconds) => seconds,
1000 None => return Self::MIN,
1001 };
1002 }
1003
1004 Self::new_unchecked(seconds, nanoseconds)
1005 }
1006
1007 /// Computes `self * rhs`, saturating if an overflow occurred.
1008 ///
1009 /// ```rust
1010 /// # use time::{Duration, ext::NumericalDuration};
1011 /// assert_eq!(5.seconds().saturating_mul(2), 10.seconds());
1012 /// assert_eq!(5.seconds().saturating_mul(-2), (-10).seconds());
1013 /// assert_eq!(5.seconds().saturating_mul(0), Duration::ZERO);
1014 /// assert_eq!(Duration::MAX.saturating_mul(2), Duration::MAX);
1015 /// assert_eq!(Duration::MIN.saturating_mul(2), Duration::MIN);
1016 /// assert_eq!(Duration::MAX.saturating_mul(-2), Duration::MIN);
1017 /// assert_eq!(Duration::MIN.saturating_mul(-2), Duration::MAX);
1018 /// ```
1019 pub const fn saturating_mul(self, rhs: i32) -> Self {
1020 // Multiply nanoseconds as i64, because it cannot overflow that way.
1021 let total_nanos = self.nanoseconds as i64 * rhs as i64;
1022 let extra_secs = total_nanos / Nanosecond.per(Second) as i64;
1023 let nanoseconds = (total_nanos % Nanosecond.per(Second) as i64) as _;
1024 let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as _);
1025 if overflow1 {
1026 if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 {
1027 return Self::MAX;
1028 }
1029 return Self::MIN;
1030 }
1031 let (seconds, overflow2) = seconds.overflowing_add(extra_secs);
1032 if overflow2 {
1033 if self.seconds > 0 && rhs > 0 {
1034 return Self::MAX;
1035 }
1036 return Self::MIN;
1037 }
1038
1039 Self::new_unchecked(seconds, nanoseconds)
1040 }
1041 // endregion saturating arithmetic
1042
1043 /// Runs a closure, returning the duration of time it took to run. The return value of the
1044 /// closure is provided in the second part of the tuple.
1045 #[cfg(feature = "std")]
1046 pub fn time_fn<T>(f: impl FnOnce() -> T) -> (Self, T) {
1047 let start = Instant::now();
1048 let return_value = f();
1049 let end = Instant::now();
1050
1051 (end - start, return_value)
1052 }
1053}
1054
1055// region: trait impls
1056/// The format returned by this implementation is not stable and must not be relied upon.
1057///
1058/// By default this produces an exact, full-precision printout of the duration.
1059/// For a concise, rounded printout instead, you can use the `.N` format specifier:
1060///
1061/// ```
1062/// # use time::Duration;
1063/// #
1064/// let duration = Duration::new(123456, 789011223);
1065/// println!("{duration:.3}");
1066/// ```
1067///
1068/// For the purposes of this implementation, a day is exactly 24 hours and a minute is exactly 60
1069/// seconds.
1070impl fmt::Display for Duration {
1071 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1072 if self.is_negative() {
1073 f.write_str("-")?;
1074 }
1075
1076 if let Some(_precision) = f.precision() {
1077 // Concise, rounded representation.
1078
1079 if self.is_zero() {
1080 // Write a zero value with the requested precision.
1081 return (0.).fmt(f).and_then(|_| f.write_str("s"));
1082 }
1083
1084 /// Format the first item that produces a value greater than 1 and then break.
1085 macro_rules! item {
1086 ($name:literal, $value:expr) => {
1087 let value = $value;
1088 if value >= 1.0 {
1089 return value.fmt(f).and_then(|_| f.write_str($name));
1090 }
1091 };
1092 }
1093
1094 // Even if this produces a de-normal float, because we're rounding we don't really care.
1095 let seconds = self.unsigned_abs().as_secs_f64();
1096
1097 item!("d", seconds / Second.per(Day) as f64);
1098 item!("h", seconds / Second.per(Hour) as f64);
1099 item!("m", seconds / Second.per(Minute) as f64);
1100 item!("s", seconds);
1101 item!("ms", seconds * Millisecond.per(Second) as f64);
1102 item!("µs", seconds * Microsecond.per(Second) as f64);
1103 item!("ns", seconds * Nanosecond.per(Second) as f64);
1104 } else {
1105 // Precise, but verbose representation.
1106
1107 if self.is_zero() {
1108 return f.write_str("0s");
1109 }
1110
1111 /// Format a single item.
1112 macro_rules! item {
1113 ($name:literal, $value:expr) => {
1114 match $value {
1115 0 => Ok(()),
1116 value => value.fmt(f).and_then(|_| f.write_str($name)),
1117 }
1118 };
1119 }
1120
1121 let seconds = self.seconds.unsigned_abs();
1122 let nanoseconds = self.nanoseconds.unsigned_abs();
1123
1124 item!("d", seconds / Second.per(Day) as u64)?;
1125 item!(
1126 "h",
1127 seconds / Second.per(Hour) as u64 % Hour.per(Day) as u64
1128 )?;
1129 item!(
1130 "m",
1131 seconds / Second.per(Minute) as u64 % Minute.per(Hour) as u64
1132 )?;
1133 item!("s", seconds % Second.per(Minute) as u64)?;
1134 item!("ms", nanoseconds / Nanosecond.per(Millisecond))?;
1135 item!(
1136 "µs",
1137 nanoseconds / Nanosecond.per(Microsecond) as u32
1138 % Microsecond.per(Millisecond) as u32
1139 )?;
1140 item!("ns", nanoseconds % Nanosecond.per(Microsecond) as u32)?;
1141 }
1142
1143 Ok(())
1144 }
1145}
1146
1147impl TryFrom<StdDuration> for Duration {
1148 type Error = error::ConversionRange;
1149
1150 fn try_from(original: StdDuration) -> Result<Self, error::ConversionRange> {
1151 Ok(Self::new(
1152 seconds:original
1153 .as_secs()
1154 .try_into()
1155 .map_err(|_| error::ConversionRange)?,
1156 nanoseconds:original.subsec_nanos() as _,
1157 ))
1158 }
1159}
1160
1161impl TryFrom<Duration> for StdDuration {
1162 type Error = error::ConversionRange;
1163
1164 fn try_from(duration: Duration) -> Result<Self, error::ConversionRange> {
1165 Ok(Self::new(
1166 secs:duration
1167 .seconds
1168 .try_into()
1169 .map_err(|_| error::ConversionRange)?,
1170 nanos:duration
1171 .nanoseconds
1172 .try_into()
1173 .map_err(|_| error::ConversionRange)?,
1174 ))
1175 }
1176}
1177
1178impl Add for Duration {
1179 type Output = Self;
1180
1181 fn add(self, rhs: Self) -> Self::Output {
1182 self.checked_add(rhs)
1183 .expect(msg:"overflow when adding durations")
1184 }
1185}
1186
1187impl Add<StdDuration> for Duration {
1188 type Output = Self;
1189
1190 fn add(self, std_duration: StdDuration) -> Self::Output {
1191 self + Self::try_from(std_duration)
1192 .expect(msg:"overflow converting `std::time::Duration` to `time::Duration`")
1193 }
1194}
1195
1196impl Add<Duration> for StdDuration {
1197 type Output = Duration;
1198
1199 fn add(self, rhs: Duration) -> Self::Output {
1200 rhs + self
1201 }
1202}
1203
1204impl_add_assign!(Duration: Self, StdDuration);
1205
1206impl AddAssign<Duration> for StdDuration {
1207 fn add_assign(&mut self, rhs: Duration) {
1208 *self = (*self + rhs).try_into().expect(
1209 msg:"Cannot represent a resulting duration in std. Try `let x = x + rhs;`, which will \
1210msg: change the type.",
1211 );
1212 }
1213}
1214
1215impl Neg for Duration {
1216 type Output = Self;
1217
1218 fn neg(self) -> Self::Output {
1219 Self::new_unchecked(-self.seconds, -self.nanoseconds)
1220 }
1221}
1222
1223impl Sub for Duration {
1224 type Output = Self;
1225
1226 fn sub(self, rhs: Self) -> Self::Output {
1227 self.checked_sub(rhs)
1228 .expect(msg:"overflow when subtracting durations")
1229 }
1230}
1231
1232impl Sub<StdDuration> for Duration {
1233 type Output = Self;
1234
1235 fn sub(self, rhs: StdDuration) -> Self::Output {
1236 self - Self::try_from(rhs)
1237 .expect(msg:"overflow converting `std::time::Duration` to `time::Duration`")
1238 }
1239}
1240
1241impl Sub<Duration> for StdDuration {
1242 type Output = Duration;
1243
1244 fn sub(self, rhs: Duration) -> Self::Output {
1245 Duration::try_from(self)
1246 .expect(msg:"overflow converting `std::time::Duration` to `time::Duration`")
1247 - rhs
1248 }
1249}
1250
1251impl_sub_assign!(Duration: Self, StdDuration);
1252
1253impl SubAssign<Duration> for StdDuration {
1254 fn sub_assign(&mut self, rhs: Duration) {
1255 *self = (*self - rhs).try_into().expect(
1256 msg:"Cannot represent a resulting duration in std. Try `let x = x - rhs;`, which will \
1257msg: change the type.",
1258 );
1259 }
1260}
1261
1262/// Implement `Mul` (reflexively) and `Div` for `Duration` for various types.
1263macro_rules! duration_mul_div_int {
1264 ($($type:ty),+) => {$(
1265 impl Mul<$type> for Duration {
1266 type Output = Self;
1267
1268 fn mul(self, rhs: $type) -> Self::Output {
1269 Self::nanoseconds_i128(
1270 self.whole_nanoseconds()
1271 .checked_mul(rhs as _)
1272 .expect("overflow when multiplying duration")
1273 )
1274 }
1275 }
1276
1277 impl Mul<Duration> for $type {
1278 type Output = Duration;
1279
1280 fn mul(self, rhs: Duration) -> Self::Output {
1281 rhs * self
1282 }
1283 }
1284
1285 impl Div<$type> for Duration {
1286 type Output = Self;
1287
1288 fn div(self, rhs: $type) -> Self::Output {
1289 Self::nanoseconds_i128(self.whole_nanoseconds() / rhs as i128)
1290 }
1291 }
1292 )+};
1293}
1294duration_mul_div_int![i8, i16, i32, u8, u16, u32];
1295
1296impl Mul<f32> for Duration {
1297 type Output = Self;
1298
1299 fn mul(self, rhs: f32) -> Self::Output {
1300 Self::seconds_f32(self.as_seconds_f32() * rhs)
1301 }
1302}
1303
1304impl Mul<Duration> for f32 {
1305 type Output = Duration;
1306
1307 fn mul(self, rhs: Duration) -> Self::Output {
1308 rhs * self
1309 }
1310}
1311
1312impl Mul<f64> for Duration {
1313 type Output = Self;
1314
1315 fn mul(self, rhs: f64) -> Self::Output {
1316 Self::seconds_f64(self.as_seconds_f64() * rhs)
1317 }
1318}
1319
1320impl Mul<Duration> for f64 {
1321 type Output = Duration;
1322
1323 fn mul(self, rhs: Duration) -> Self::Output {
1324 rhs * self
1325 }
1326}
1327
1328impl_mul_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
1329
1330impl Div<f32> for Duration {
1331 type Output = Self;
1332
1333 fn div(self, rhs: f32) -> Self::Output {
1334 Self::seconds_f32(self.as_seconds_f32() / rhs)
1335 }
1336}
1337
1338impl Div<f64> for Duration {
1339 type Output = Self;
1340
1341 fn div(self, rhs: f64) -> Self::Output {
1342 Self::seconds_f64(self.as_seconds_f64() / rhs)
1343 }
1344}
1345
1346impl_div_assign!(Duration: i8, i16, i32, u8, u16, u32, f32, f64);
1347
1348impl Div for Duration {
1349 type Output = f64;
1350
1351 fn div(self, rhs: Self) -> Self::Output {
1352 self.as_seconds_f64() / rhs.as_seconds_f64()
1353 }
1354}
1355
1356impl Div<StdDuration> for Duration {
1357 type Output = f64;
1358
1359 fn div(self, rhs: StdDuration) -> Self::Output {
1360 self.as_seconds_f64() / rhs.as_secs_f64()
1361 }
1362}
1363
1364impl Div<Duration> for StdDuration {
1365 type Output = f64;
1366
1367 fn div(self, rhs: Duration) -> Self::Output {
1368 self.as_secs_f64() / rhs.as_seconds_f64()
1369 }
1370}
1371
1372impl PartialEq<StdDuration> for Duration {
1373 fn eq(&self, rhs: &StdDuration) -> bool {
1374 Ok(*self) == Self::try_from(*rhs)
1375 }
1376}
1377
1378impl PartialEq<Duration> for StdDuration {
1379 fn eq(&self, rhs: &Duration) -> bool {
1380 rhs == self
1381 }
1382}
1383
1384impl PartialOrd<StdDuration> for Duration {
1385 fn partial_cmp(&self, rhs: &StdDuration) -> Option<Ordering> {
1386 if rhs.as_secs() > i64::MAX as _ {
1387 return Some(Ordering::Less);
1388 }
1389
1390 Some(
1391 self.seconds
1392 .cmp(&(rhs.as_secs() as _))
1393 .then_with(|| self.nanoseconds.cmp(&(rhs.subsec_nanos() as _))),
1394 )
1395 }
1396}
1397
1398impl PartialOrd<Duration> for StdDuration {
1399 fn partial_cmp(&self, rhs: &Duration) -> Option<Ordering> {
1400 rhs.partial_cmp(self).map(Ordering::reverse)
1401 }
1402}
1403
1404impl Sum for Duration {
1405 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1406 iter.reduce(|a: Duration, b: Duration| a + b).unwrap_or_default()
1407 }
1408}
1409
1410impl<'a> Sum<&'a Self> for Duration {
1411 fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
1412 iter.copied().sum()
1413 }
1414}
1415// endregion trait impls
1416