time/duration.rs
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, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
7use core::time::Duration as StdDuration;
8#[cfg(feature = "std")]
9use std::time::SystemTime;
10
11use deranged::RangedI32;
12use num_conv::prelude::*;
13
14#[cfg(feature = "std")]
15#[expect(deprecated)]
16use crate::Instant;
17use crate::convert::*;
18use crate::error;
19use crate::internal_macros::const_try_opt;
20
21#[derive(Debug)]
22enum FloatConstructorError {
23 Nan,
24 NegOverflow,
25 PosOverflow,
26}
27
28/// By explicitly inserting this enum where padding is expected, the compiler is able to better
29/// perform niche value optimization.
30#[repr(u32)]
31#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
32pub(crate) enum Padding {
33 #[allow(clippy::missing_docs_in_private_items)]
34 Optimize,
35}
36
37/// The type of the `nanosecond` field of `Duration`.
38type Nanoseconds =
39 RangedI32<{ -Nanosecond::per_t::<i32>(Second) + 1 }, { Nanosecond::per_t::<i32>(Second) - 1 }>;
40
41/// A span of time with nanosecond precision.
42///
43/// Each `Duration` is composed of a whole number of seconds and a fractional part represented in
44/// nanoseconds.
45///
46/// This implementation allows for negative durations, unlike [`core::time::Duration`].
47#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
48pub struct Duration {
49 /// Number of whole seconds.
50 seconds: i64,
51 /// Number of nanoseconds within the second. The sign always matches the `seconds` field.
52 // Sign must match that of `seconds` (though this is not a safety requirement).
53 nanoseconds: Nanoseconds,
54 padding: Padding,
55}
56
57impl fmt::Debug for Duration {
58 #[inline]
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 f.debug_struct("Duration")
61 .field("seconds", &self.seconds)
62 .field("nanoseconds", &self.nanoseconds)
63 .finish()
64 }
65}
66
67impl Default for Duration {
68 #[inline]
69 fn default() -> Self {
70 Self {
71 seconds: 0,
72 nanoseconds: Nanoseconds::new_static::<0>(),
73 padding: Padding::Optimize,
74 }
75 }
76}
77
78/// This is adapted from the [`std` implementation][std], which uses mostly bit
79/// operations to ensure the highest precision:
80///
81/// Changes from `std` are marked and explained below.
82///
83/// [std]: https://github.com/rust-lang/rust/blob/3a37c2f0523c87147b64f1b8099fc9df22e8c53e/library/core/src/time.rs#L1262-L1340
84#[rustfmt::skip] // Skip `rustfmt` because it reformats the arguments of the macro weirdly.
85macro_rules! try_from_secs {
86 (
87 secs = $secs: expr,
88 mantissa_bits = $mant_bits: literal,
89 exponent_bits = $exp_bits: literal,
90 offset = $offset: literal,
91 bits_ty = $bits_ty:ty,
92 bits_ty_signed = $bits_ty_signed:ty,
93 double_ty = $double_ty:ty,
94 float_ty = $float_ty:ty,
95 ) => {{
96 'value: {
97 const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2;
98 const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1;
99 const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1;
100
101 // Change from std: No error check for negative values necessary.
102
103 let bits = $secs.to_bits();
104 let mant = (bits & MANT_MASK) | (MANT_MASK + 1);
105 let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP;
106
107 let (secs, nanos) = if exp < -31 {
108 // the input represents less than 1ns and can not be rounded to it
109 (0u64, 0u32)
110 } else if exp < 0 {
111 // the input is less than 1 second
112 let t = (mant as $double_ty) << ($offset + exp);
113 let nanos_offset = $mant_bits + $offset;
114 #[allow(trivial_numeric_casts)]
115 let nanos_tmp = Nanosecond::per_t::<u128>(Second) * t as u128;
116 let nanos = (nanos_tmp >> nanos_offset) as u32;
117
118 let rem_mask = (1 << nanos_offset) - 1;
119 let rem_msb_mask = 1 << (nanos_offset - 1);
120 let rem = nanos_tmp & rem_mask;
121 let is_tie = rem == rem_msb_mask;
122 let is_even = (nanos & 1) == 0;
123 let rem_msb = nanos_tmp & rem_msb_mask == 0;
124 let add_ns = !(rem_msb || (is_even && is_tie));
125
126 // f32 does not have enough precision to trigger the second branch
127 // since it can not represent numbers between 0.999_999_940_395 and 1.0.
128 let nanos = nanos + add_ns as u32;
129 if ($mant_bits == 23) || (nanos != Nanosecond::per_t::<u32>(Second)) {
130 (0, nanos)
131 } else {
132 (1, 0)
133 }
134 } else if exp < $mant_bits {
135 #[allow(trivial_numeric_casts)]
136 let secs = (mant >> ($mant_bits - exp)) as u64;
137 let t = ((mant << exp) & MANT_MASK) as $double_ty;
138 let nanos_offset = $mant_bits;
139 let nanos_tmp = Nanosecond::per_t::<$double_ty>(Second) * t;
140 let nanos = (nanos_tmp >> nanos_offset) as u32;
141
142 let rem_mask = (1 << nanos_offset) - 1;
143 let rem_msb_mask = 1 << (nanos_offset - 1);
144 let rem = nanos_tmp & rem_mask;
145 let is_tie = rem == rem_msb_mask;
146 let is_even = (nanos & 1) == 0;
147 let rem_msb = nanos_tmp & rem_msb_mask == 0;
148 let add_ns = !(rem_msb || (is_even && is_tie));
149
150 // f32 does not have enough precision to trigger the second branch.
151 // For example, it can not represent numbers between 1.999_999_880...
152 // and 2.0. Bigger values result in even smaller precision of the
153 // fractional part.
154 let nanos = nanos + add_ns as u32;
155 if ($mant_bits == 23) || (nanos != Nanosecond::per_t::<u32>(Second)) {
156 (secs, nanos)
157 } else {
158 (secs + 1, 0)
159 }
160 } else if exp < 63 {
161 // Change from std: The exponent here is 63 instead of 64,
162 // because i64::MAX + 1 is 2^63.
163
164 // the input has no fractional part
165 #[allow(trivial_numeric_casts)]
166 let secs = (mant as u64) << (exp - $mant_bits);
167 (secs, 0)
168 } else if bits == (i64::MIN as $float_ty).to_bits() {
169 // Change from std: Signed integers are asymmetrical in that
170 // iN::MIN is -iN::MAX - 1. So for example i8 covers the
171 // following numbers -128..=127. The check above (exp < 63)
172 // doesn't cover i64::MIN as that is -2^63, so we have this
173 // additional case to handle the asymmetry of iN::MIN.
174 break 'value Ok(Self::new_ranged_unchecked(i64::MIN, Nanoseconds::new_static::<0>()));
175 } else if $secs.is_nan() {
176 // Change from std: std doesn't differentiate between the error
177 // cases.
178 break 'value Err(FloatConstructorError::Nan);
179 } else if $secs.is_sign_negative() {
180 break 'value Err(FloatConstructorError::NegOverflow);
181 } else {
182 break 'value Err(FloatConstructorError::PosOverflow);
183 };
184
185 // Change from std: All the code is mostly unmodified in that it
186 // simply calculates an unsigned integer. Here we extract the sign
187 // bit and assign it to the number. We basically manually do two's
188 // complement here, we could also use an if and just negate the
189 // numbers based on the sign, but it turns out to be quite a bit
190 // slower.
191 let mask = (bits as $bits_ty_signed) >> ($mant_bits + $exp_bits);
192 #[allow(trivial_numeric_casts)]
193 let secs_signed = ((secs as i64) ^ (mask as i64)) - (mask as i64);
194 #[allow(trivial_numeric_casts)]
195 let nanos_signed = ((nanos as i32) ^ (mask as i32)) - (mask as i32);
196 // Safety: `nanos_signed` is in range.
197 Ok(unsafe { Self::new_unchecked(secs_signed, nanos_signed) })
198 }
199 }};
200}
201
202impl Duration {
203 /// Equivalent to `0.seconds()`.
204 ///
205 /// ```rust
206 /// # use time::{Duration, ext::NumericalDuration};
207 /// assert_eq!(Duration::ZERO, 0.seconds());
208 /// ```
209 pub const ZERO: Self = Self::seconds(0);
210
211 /// Equivalent to `1.nanoseconds()`.
212 ///
213 /// ```rust
214 /// # use time::{Duration, ext::NumericalDuration};
215 /// assert_eq!(Duration::NANOSECOND, 1.nanoseconds());
216 /// ```
217 pub const NANOSECOND: Self = Self::nanoseconds(1);
218
219 /// Equivalent to `1.microseconds()`.
220 ///
221 /// ```rust
222 /// # use time::{Duration, ext::NumericalDuration};
223 /// assert_eq!(Duration::MICROSECOND, 1.microseconds());
224 /// ```
225 pub const MICROSECOND: Self = Self::microseconds(1);
226
227 /// Equivalent to `1.milliseconds()`.
228 ///
229 /// ```rust
230 /// # use time::{Duration, ext::NumericalDuration};
231 /// assert_eq!(Duration::MILLISECOND, 1.milliseconds());
232 /// ```
233 pub const MILLISECOND: Self = Self::milliseconds(1);
234
235 /// Equivalent to `1.seconds()`.
236 ///
237 /// ```rust
238 /// # use time::{Duration, ext::NumericalDuration};
239 /// assert_eq!(Duration::SECOND, 1.seconds());
240 /// ```
241 pub const SECOND: Self = Self::seconds(1);
242
243 /// Equivalent to `1.minutes()`.
244 ///
245 /// ```rust
246 /// # use time::{Duration, ext::NumericalDuration};
247 /// assert_eq!(Duration::MINUTE, 1.minutes());
248 /// ```
249 pub const MINUTE: Self = Self::minutes(1);
250
251 /// Equivalent to `1.hours()`.
252 ///
253 /// ```rust
254 /// # use time::{Duration, ext::NumericalDuration};
255 /// assert_eq!(Duration::HOUR, 1.hours());
256 /// ```
257 pub const HOUR: Self = Self::hours(1);
258
259 /// Equivalent to `1.days()`.
260 ///
261 /// ```rust
262 /// # use time::{Duration, ext::NumericalDuration};
263 /// assert_eq!(Duration::DAY, 1.days());
264 /// ```
265 pub const DAY: Self = Self::days(1);
266
267 /// Equivalent to `1.weeks()`.
268 ///
269 /// ```rust
270 /// # use time::{Duration, ext::NumericalDuration};
271 /// assert_eq!(Duration::WEEK, 1.weeks());
272 /// ```
273 pub const WEEK: Self = Self::weeks(1);
274
275 /// The minimum possible duration. Adding any negative duration to this will cause an overflow.
276 pub const MIN: Self = Self::new_ranged(i64::MIN, Nanoseconds::MIN);
277
278 /// The maximum possible duration. Adding any positive duration to this will cause an overflow.
279 pub const MAX: Self = Self::new_ranged(i64::MAX, Nanoseconds::MAX);
280
281 /// Check if a duration is exactly zero.
282 ///
283 /// ```rust
284 /// # use time::ext::NumericalDuration;
285 /// assert!(0.seconds().is_zero());
286 /// assert!(!1.nanoseconds().is_zero());
287 /// ```
288 #[inline]
289 pub const fn is_zero(self) -> bool {
290 self.seconds == 0 && self.nanoseconds.get() == 0
291 }
292
293 /// Check if a duration is negative.
294 ///
295 /// ```rust
296 /// # use time::ext::NumericalDuration;
297 /// assert!((-1).seconds().is_negative());
298 /// assert!(!0.seconds().is_negative());
299 /// assert!(!1.seconds().is_negative());
300 /// ```
301 #[inline]
302 pub const fn is_negative(self) -> bool {
303 self.seconds < 0 || self.nanoseconds.get() < 0
304 }
305
306 /// Check if a duration is positive.
307 ///
308 /// ```rust
309 /// # use time::ext::NumericalDuration;
310 /// assert!(1.seconds().is_positive());
311 /// assert!(!0.seconds().is_positive());
312 /// assert!(!(-1).seconds().is_positive());
313 /// ```
314 #[inline]
315 pub const fn is_positive(self) -> bool {
316 self.seconds > 0 || self.nanoseconds.get() > 0
317 }
318
319 /// Get the absolute value of the duration.
320 ///
321 /// This method saturates the returned value if it would otherwise overflow.
322 ///
323 /// ```rust
324 /// # use time::ext::NumericalDuration;
325 /// assert_eq!(1.seconds().abs(), 1.seconds());
326 /// assert_eq!(0.seconds().abs(), 0.seconds());
327 /// assert_eq!((-1).seconds().abs(), 1.seconds());
328 /// ```
329 #[inline]
330 pub const fn abs(self) -> Self {
331 match self.seconds.checked_abs() {
332 Some(seconds) => Self::new_ranged_unchecked(seconds, self.nanoseconds.abs()),
333 None => Self::MAX,
334 }
335 }
336
337 /// Convert the existing `Duration` to a `std::time::Duration` and its sign. This returns a
338 /// [`std::time::Duration`] and does not saturate the returned value (unlike [`Duration::abs`]).
339 ///
340 /// ```rust
341 /// # use time::ext::{NumericalDuration, NumericalStdDuration};
342 /// assert_eq!(1.seconds().unsigned_abs(), 1.std_seconds());
343 /// assert_eq!(0.seconds().unsigned_abs(), 0.std_seconds());
344 /// assert_eq!((-1).seconds().unsigned_abs(), 1.std_seconds());
345 /// ```
346 #[inline]
347 pub const fn unsigned_abs(self) -> StdDuration {
348 StdDuration::new(
349 self.seconds.unsigned_abs(),
350 self.nanoseconds.get().unsigned_abs(),
351 )
352 }
353
354 /// Create a new `Duration` without checking the validity of the components.
355 ///
356 /// # Safety
357 ///
358 /// - `nanoseconds` must be in the range `-999_999_999..=999_999_999`.
359 ///
360 /// While the sign of `nanoseconds` is required to be the same as the sign of `seconds`, this is
361 /// not a safety invariant.
362 #[inline]
363 #[track_caller]
364 pub(crate) const unsafe fn new_unchecked(seconds: i64, nanoseconds: i32) -> Self {
365 Self::new_ranged_unchecked(
366 seconds,
367 // Safety: The caller must uphold the safety invariants.
368 unsafe { Nanoseconds::new_unchecked(nanoseconds) },
369 )
370 }
371
372 /// Create a new `Duration` without checking the validity of the components.
373 #[inline]
374 #[track_caller]
375 pub(crate) const fn new_ranged_unchecked(seconds: i64, nanoseconds: Nanoseconds) -> Self {
376 if seconds < 0 {
377 debug_assert!(nanoseconds.get() <= 0);
378 } else if seconds > 0 {
379 debug_assert!(nanoseconds.get() >= 0);
380 }
381
382 Self {
383 seconds,
384 nanoseconds,
385 padding: Padding::Optimize,
386 }
387 }
388
389 /// Create a new `Duration` with the provided seconds and nanoseconds. If nanoseconds is at
390 /// least ±10<sup>9</sup>, it will wrap to the number of seconds.
391 ///
392 /// ```rust
393 /// # use time::{Duration, ext::NumericalDuration};
394 /// assert_eq!(Duration::new(1, 0), 1.seconds());
395 /// assert_eq!(Duration::new(-1, 0), (-1).seconds());
396 /// assert_eq!(Duration::new(1, 2_000_000_000), 3.seconds());
397 /// ```
398 ///
399 /// # Panics
400 ///
401 /// This may panic if an overflow occurs.
402 #[inline]
403 #[track_caller]
404 pub const fn new(mut seconds: i64, mut nanoseconds: i32) -> Self {
405 seconds = seconds
406 .checked_add(nanoseconds as i64 / Nanosecond::per_t::<i64>(Second))
407 .expect("overflow constructing `time::Duration`");
408 nanoseconds %= Nanosecond::per_t::<i32>(Second);
409
410 if seconds > 0 && nanoseconds < 0 {
411 // `seconds` cannot overflow here because it is positive.
412 seconds -= 1;
413 nanoseconds += Nanosecond::per_t::<i32>(Second);
414 } else if seconds < 0 && nanoseconds > 0 {
415 // `seconds` cannot overflow here because it is negative.
416 seconds += 1;
417 nanoseconds -= Nanosecond::per_t::<i32>(Second);
418 }
419
420 // Safety: `nanoseconds` is in range due to the modulus above.
421 unsafe { Self::new_unchecked(seconds, nanoseconds) }
422 }
423
424 /// Create a new `Duration` with the provided seconds and nanoseconds.
425 #[inline]
426 pub(crate) const fn new_ranged(mut seconds: i64, mut nanoseconds: Nanoseconds) -> Self {
427 if seconds > 0 && nanoseconds.get() < 0 {
428 // `seconds` cannot overflow here because it is positive.
429 seconds -= 1;
430 // Safety: `nanoseconds` is negative with a maximum of 999,999,999, so adding a billion
431 // to it is guaranteed to result in an in-range value.
432 nanoseconds = unsafe {
433 Nanoseconds::new_unchecked(nanoseconds.get() + Nanosecond::per_t::<i32>(Second))
434 };
435 } else if seconds < 0 && nanoseconds.get() > 0 {
436 // `seconds` cannot overflow here because it is negative.
437 seconds += 1;
438 // Safety: `nanoseconds` is positive with a minimum of -999,999,999, so subtracting a
439 // billion from it is guaranteed to result in an in-range value.
440 nanoseconds = unsafe {
441 Nanoseconds::new_unchecked(nanoseconds.get() - Nanosecond::per_t::<i32>(Second))
442 };
443 }
444
445 Self::new_ranged_unchecked(seconds, nanoseconds)
446 }
447
448 /// Create a new `Duration` with the given number of weeks. Equivalent to
449 /// `Duration::seconds(weeks * 604_800)`.
450 ///
451 /// ```rust
452 /// # use time::{Duration, ext::NumericalDuration};
453 /// assert_eq!(Duration::weeks(1), 604_800.seconds());
454 /// ```
455 ///
456 /// # Panics
457 ///
458 /// This may panic if an overflow occurs.
459 #[inline]
460 #[track_caller]
461 pub const fn weeks(weeks: i64) -> Self {
462 Self::seconds(
463 weeks
464 .checked_mul(Second::per_t(Week))
465 .expect("overflow constructing `time::Duration`"),
466 )
467 }
468
469 /// Create a new `Duration` with the given number of days. Equivalent to
470 /// `Duration::seconds(days * 86_400)`.
471 ///
472 /// ```rust
473 /// # use time::{Duration, ext::NumericalDuration};
474 /// assert_eq!(Duration::days(1), 86_400.seconds());
475 /// ```
476 ///
477 /// # Panics
478 ///
479 /// This may panic if an overflow occurs.
480 #[inline]
481 #[track_caller]
482 pub const fn days(days: i64) -> Self {
483 Self::seconds(
484 days.checked_mul(Second::per_t(Day))
485 .expect("overflow constructing `time::Duration`"),
486 )
487 }
488
489 /// Create a new `Duration` with the given number of hours. Equivalent to
490 /// `Duration::seconds(hours * 3_600)`.
491 ///
492 /// ```rust
493 /// # use time::{Duration, ext::NumericalDuration};
494 /// assert_eq!(Duration::hours(1), 3_600.seconds());
495 /// ```
496 ///
497 /// # Panics
498 ///
499 /// This may panic if an overflow occurs.
500 #[inline]
501 #[track_caller]
502 pub const fn hours(hours: i64) -> Self {
503 Self::seconds(
504 hours
505 .checked_mul(Second::per_t(Hour))
506 .expect("overflow constructing `time::Duration`"),
507 )
508 }
509
510 /// Create a new `Duration` with the given number of minutes. Equivalent to
511 /// `Duration::seconds(minutes * 60)`.
512 ///
513 /// ```rust
514 /// # use time::{Duration, ext::NumericalDuration};
515 /// assert_eq!(Duration::minutes(1), 60.seconds());
516 /// ```
517 ///
518 /// # Panics
519 ///
520 /// This may panic if an overflow occurs.
521 #[inline]
522 #[track_caller]
523 pub const fn minutes(minutes: i64) -> Self {
524 Self::seconds(
525 minutes
526 .checked_mul(Second::per_t(Minute))
527 .expect("overflow constructing `time::Duration`"),
528 )
529 }
530
531 /// Create a new `Duration` with the given number of seconds.
532 ///
533 /// ```rust
534 /// # use time::{Duration, ext::NumericalDuration};
535 /// assert_eq!(Duration::seconds(1), 1_000.milliseconds());
536 /// ```
537 #[inline]
538 pub const fn seconds(seconds: i64) -> Self {
539 Self::new_ranged_unchecked(seconds, Nanoseconds::new_static::<0>())
540 }
541
542 /// Create a new `Duration` from the specified number of seconds represented as `f64`.
543 ///
544 /// If the value is `NaN` or out of bounds, an error is returned that can be handled in the
545 /// desired manner by the caller.
546 #[inline]
547 const fn try_seconds_f64(seconds: f64) -> Result<Self, FloatConstructorError> {
548 try_from_secs!(
549 secs = seconds,
550 mantissa_bits = 52,
551 exponent_bits = 11,
552 offset = 44,
553 bits_ty = u64,
554 bits_ty_signed = i64,
555 double_ty = u128,
556 float_ty = f64,
557 )
558 }
559
560 /// Create a new `Duration` from the specified number of seconds represented as `f32`.
561 ///
562 /// If the value is `NaN` or out of bounds, an error is returned that can be handled in the
563 /// desired manner by the caller.
564 #[inline]
565 const fn try_seconds_f32(seconds: f32) -> Result<Self, FloatConstructorError> {
566 try_from_secs!(
567 secs = seconds,
568 mantissa_bits = 23,
569 exponent_bits = 8,
570 offset = 41,
571 bits_ty = u32,
572 bits_ty_signed = i32,
573 double_ty = u64,
574 float_ty = f32,
575 )
576 }
577
578 /// Creates a new `Duration` from the specified number of seconds represented as `f64`.
579 ///
580 /// ```rust
581 /// # use time::{Duration, ext::NumericalDuration};
582 /// assert_eq!(Duration::seconds_f64(0.5), 0.5.seconds());
583 /// assert_eq!(Duration::seconds_f64(-0.5), (-0.5).seconds());
584 /// ```
585 #[inline(never)]
586 #[track_caller]
587 pub const fn seconds_f64(seconds: f64) -> Self {
588 match Self::try_seconds_f64(seconds) {
589 Ok(duration) => duration,
590 Err(FloatConstructorError::Nan) => {
591 panic!("passed NaN to `time::Duration::seconds_f64`");
592 }
593 Err(FloatConstructorError::NegOverflow | FloatConstructorError::PosOverflow) => {
594 panic!("overflow constructing `time::Duration`");
595 }
596 }
597 }
598
599 /// Creates a new `Duration` from the specified number of seconds represented as `f32`.
600 ///
601 /// ```rust
602 /// # use time::{Duration, ext::NumericalDuration};
603 /// assert_eq!(Duration::seconds_f32(0.5), 0.5.seconds());
604 /// assert_eq!(Duration::seconds_f32(-0.5), (-0.5).seconds());
605 /// ```
606 #[inline]
607 #[track_caller]
608 pub const fn seconds_f32(seconds: f32) -> Self {
609 match Self::try_seconds_f32(seconds) {
610 Ok(duration) => duration,
611 Err(FloatConstructorError::Nan) => {
612 panic!("passed NaN to `time::Duration::seconds_f32`");
613 }
614 Err(FloatConstructorError::NegOverflow | FloatConstructorError::PosOverflow) => {
615 panic!("overflow constructing `time::Duration`");
616 }
617 }
618 }
619
620 /// Creates a new `Duration` from the specified number of seconds
621 /// represented as `f64`. Any values that are out of bounds are saturated at
622 /// the minimum or maximum respectively. `NaN` gets turned into a `Duration`
623 /// of 0 seconds.
624 ///
625 /// ```rust
626 /// # use time::{Duration, ext::NumericalDuration};
627 /// assert_eq!(Duration::saturating_seconds_f64(0.5), 0.5.seconds());
628 /// assert_eq!(Duration::saturating_seconds_f64(-0.5), (-0.5).seconds());
629 /// assert_eq!(
630 /// Duration::saturating_seconds_f64(f64::NAN),
631 /// Duration::new(0, 0),
632 /// );
633 /// assert_eq!(
634 /// Duration::saturating_seconds_f64(f64::NEG_INFINITY),
635 /// Duration::MIN,
636 /// );
637 /// assert_eq!(
638 /// Duration::saturating_seconds_f64(f64::INFINITY),
639 /// Duration::MAX,
640 /// );
641 /// ```
642 #[inline(never)]
643 pub const fn saturating_seconds_f64(seconds: f64) -> Self {
644 match Self::try_seconds_f64(seconds) {
645 Ok(duration) => duration,
646 Err(FloatConstructorError::Nan) => Self::ZERO,
647 Err(FloatConstructorError::NegOverflow) => Self::MIN,
648 Err(FloatConstructorError::PosOverflow) => Self::MAX,
649 }
650 }
651
652 /// Creates a new `Duration` from the specified number of seconds
653 /// represented as `f32`. Any values that are out of bounds are saturated at
654 /// the minimum or maximum respectively. `NaN` gets turned into a `Duration`
655 /// of 0 seconds.
656 ///
657 /// ```rust
658 /// # use time::{Duration, ext::NumericalDuration};
659 /// assert_eq!(Duration::saturating_seconds_f32(0.5), 0.5.seconds());
660 /// assert_eq!(Duration::saturating_seconds_f32(-0.5), (-0.5).seconds());
661 /// assert_eq!(
662 /// Duration::saturating_seconds_f32(f32::NAN),
663 /// Duration::new(0, 0),
664 /// );
665 /// assert_eq!(
666 /// Duration::saturating_seconds_f32(f32::NEG_INFINITY),
667 /// Duration::MIN,
668 /// );
669 /// assert_eq!(
670 /// Duration::saturating_seconds_f32(f32::INFINITY),
671 /// Duration::MAX,
672 /// );
673 /// ```
674 #[inline]
675 pub const fn saturating_seconds_f32(seconds: f32) -> Self {
676 match Self::try_seconds_f32(seconds) {
677 Ok(duration) => duration,
678 Err(FloatConstructorError::Nan) => Self::ZERO,
679 Err(FloatConstructorError::NegOverflow) => Self::MIN,
680 Err(FloatConstructorError::PosOverflow) => Self::MAX,
681 }
682 }
683
684 /// Creates a new `Duration` from the specified number of seconds
685 /// represented as `f64`. Returns `None` if the `Duration` can't be
686 /// represented.
687 ///
688 /// ```rust
689 /// # use time::{Duration, ext::NumericalDuration};
690 /// assert_eq!(Duration::checked_seconds_f64(0.5), Some(0.5.seconds()));
691 /// assert_eq!(Duration::checked_seconds_f64(-0.5), Some((-0.5).seconds()));
692 /// assert_eq!(Duration::checked_seconds_f64(f64::NAN), None);
693 /// assert_eq!(Duration::checked_seconds_f64(f64::NEG_INFINITY), None);
694 /// assert_eq!(Duration::checked_seconds_f64(f64::INFINITY), None);
695 /// ```
696 #[inline]
697 pub const fn checked_seconds_f64(seconds: f64) -> Option<Self> {
698 match Self::try_seconds_f64(seconds) {
699 Ok(duration) => Some(duration),
700 Err(_) => None,
701 }
702 }
703
704 /// Creates a new `Duration` from the specified number of seconds
705 /// represented as `f32`. Returns `None` if the `Duration` can't be
706 /// represented.
707 ///
708 /// ```rust
709 /// # use time::{Duration, ext::NumericalDuration};
710 /// assert_eq!(Duration::checked_seconds_f32(0.5), Some(0.5.seconds()));
711 /// assert_eq!(Duration::checked_seconds_f32(-0.5), Some((-0.5).seconds()));
712 /// assert_eq!(Duration::checked_seconds_f32(f32::NAN), None);
713 /// assert_eq!(Duration::checked_seconds_f32(f32::NEG_INFINITY), None);
714 /// assert_eq!(Duration::checked_seconds_f32(f32::INFINITY), None);
715 /// ```
716 #[inline]
717 pub const fn checked_seconds_f32(seconds: f32) -> Option<Self> {
718 match Self::try_seconds_f32(seconds) {
719 Ok(duration) => Some(duration),
720 Err(_) => None,
721 }
722 }
723
724 /// Create a new `Duration` with the given number of milliseconds.
725 ///
726 /// ```rust
727 /// # use time::{Duration, ext::NumericalDuration};
728 /// assert_eq!(Duration::milliseconds(1), 1_000.microseconds());
729 /// assert_eq!(Duration::milliseconds(-1), (-1_000).microseconds());
730 /// ```
731 #[inline]
732 pub const fn milliseconds(milliseconds: i64) -> Self {
733 // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
734 unsafe {
735 Self::new_unchecked(
736 milliseconds / Millisecond::per_t::<i64>(Second),
737 (milliseconds % Millisecond::per_t::<i64>(Second)
738 * Nanosecond::per_t::<i64>(Millisecond)) as i32,
739 )
740 }
741 }
742
743 /// Create a new `Duration` with the given number of microseconds.
744 ///
745 /// ```rust
746 /// # use time::{Duration, ext::NumericalDuration};
747 /// assert_eq!(Duration::microseconds(1), 1_000.nanoseconds());
748 /// assert_eq!(Duration::microseconds(-1), (-1_000).nanoseconds());
749 /// ```
750 #[inline]
751 pub const fn microseconds(microseconds: i64) -> Self {
752 // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
753 unsafe {
754 Self::new_unchecked(
755 microseconds / Microsecond::per_t::<i64>(Second),
756 (microseconds % Microsecond::per_t::<i64>(Second)
757 * Nanosecond::per_t::<i64>(Microsecond)) as i32,
758 )
759 }
760 }
761
762 /// Create a new `Duration` with the given number of nanoseconds.
763 ///
764 /// ```rust
765 /// # use time::{Duration, ext::NumericalDuration};
766 /// assert_eq!(Duration::nanoseconds(1), 1.microseconds() / 1_000);
767 /// assert_eq!(Duration::nanoseconds(-1), (-1).microseconds() / 1_000);
768 /// ```
769 #[inline]
770 pub const fn nanoseconds(nanoseconds: i64) -> Self {
771 // Safety: `nanoseconds` is guaranteed to be in range because of the modulus.
772 unsafe {
773 Self::new_unchecked(
774 nanoseconds / Nanosecond::per_t::<i64>(Second),
775 (nanoseconds % Nanosecond::per_t::<i64>(Second)) as i32,
776 )
777 }
778 }
779
780 /// Create a new `Duration` with the given number of nanoseconds.
781 ///
782 /// ```rust
783 /// # use time::{Duration, ext::NumericalDuration};
784 /// assert_eq!(
785 /// Duration::nanoseconds_i128(1_234_567_890),
786 /// 1.seconds() + 234_567_890.nanoseconds()
787 /// );
788 /// ```
789 ///
790 /// # Panics
791 ///
792 /// This may panic if an overflow occurs. This may happen because the input range cannot be
793 /// fully mapped to the output.
794 #[inline]
795 #[track_caller]
796 pub const fn nanoseconds_i128(nanoseconds: i128) -> Self {
797 let seconds = nanoseconds / Nanosecond::per_t::<i128>(Second);
798 let nanoseconds = nanoseconds % Nanosecond::per_t::<i128>(Second);
799
800 if seconds > i64::MAX as i128 || seconds < i64::MIN as i128 {
801 panic!("overflow constructing `time::Duration`");
802 }
803
804 // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
805 unsafe { Self::new_unchecked(seconds as i64, nanoseconds as i32) }
806 }
807
808 /// Get the number of whole weeks in the duration.
809 ///
810 /// ```rust
811 /// # use time::ext::NumericalDuration;
812 /// assert_eq!(1.weeks().whole_weeks(), 1);
813 /// assert_eq!((-1).weeks().whole_weeks(), -1);
814 /// assert_eq!(6.days().whole_weeks(), 0);
815 /// assert_eq!((-6).days().whole_weeks(), 0);
816 /// ```
817 #[inline]
818 pub const fn whole_weeks(self) -> i64 {
819 self.whole_seconds() / Second::per_t::<i64>(Week)
820 }
821
822 /// Get the number of whole days in the duration.
823 ///
824 /// ```rust
825 /// # use time::ext::NumericalDuration;
826 /// assert_eq!(1.days().whole_days(), 1);
827 /// assert_eq!((-1).days().whole_days(), -1);
828 /// assert_eq!(23.hours().whole_days(), 0);
829 /// assert_eq!((-23).hours().whole_days(), 0);
830 /// ```
831 #[inline]
832 pub const fn whole_days(self) -> i64 {
833 self.whole_seconds() / Second::per_t::<i64>(Day)
834 }
835
836 /// Get the number of whole hours in the duration.
837 ///
838 /// ```rust
839 /// # use time::ext::NumericalDuration;
840 /// assert_eq!(1.hours().whole_hours(), 1);
841 /// assert_eq!((-1).hours().whole_hours(), -1);
842 /// assert_eq!(59.minutes().whole_hours(), 0);
843 /// assert_eq!((-59).minutes().whole_hours(), 0);
844 /// ```
845 #[inline]
846 pub const fn whole_hours(self) -> i64 {
847 self.whole_seconds() / Second::per_t::<i64>(Hour)
848 }
849
850 /// Get the number of whole minutes in the duration.
851 ///
852 /// ```rust
853 /// # use time::ext::NumericalDuration;
854 /// assert_eq!(1.minutes().whole_minutes(), 1);
855 /// assert_eq!((-1).minutes().whole_minutes(), -1);
856 /// assert_eq!(59.seconds().whole_minutes(), 0);
857 /// assert_eq!((-59).seconds().whole_minutes(), 0);
858 /// ```
859 #[inline]
860 pub const fn whole_minutes(self) -> i64 {
861 self.whole_seconds() / Second::per_t::<i64>(Minute)
862 }
863
864 /// Get the number of whole seconds in the duration.
865 ///
866 /// ```rust
867 /// # use time::ext::NumericalDuration;
868 /// assert_eq!(1.seconds().whole_seconds(), 1);
869 /// assert_eq!((-1).seconds().whole_seconds(), -1);
870 /// assert_eq!(1.minutes().whole_seconds(), 60);
871 /// assert_eq!((-1).minutes().whole_seconds(), -60);
872 /// ```
873 #[inline]
874 pub const fn whole_seconds(self) -> i64 {
875 self.seconds
876 }
877
878 /// Get the number of fractional seconds in the duration.
879 ///
880 /// ```rust
881 /// # use time::ext::NumericalDuration;
882 /// assert_eq!(1.5.seconds().as_seconds_f64(), 1.5);
883 /// assert_eq!((-1.5).seconds().as_seconds_f64(), -1.5);
884 /// ```
885 #[inline]
886 pub const fn as_seconds_f64(self) -> f64 {
887 self.seconds as f64 + self.nanoseconds.get() as f64 / Nanosecond::per_t::<f64>(Second)
888 }
889
890 /// Get the number of fractional seconds in the duration.
891 ///
892 /// ```rust
893 /// # use time::ext::NumericalDuration;
894 /// assert_eq!(1.5.seconds().as_seconds_f32(), 1.5);
895 /// assert_eq!((-1.5).seconds().as_seconds_f32(), -1.5);
896 /// ```
897 #[inline]
898 pub const fn as_seconds_f32(self) -> f32 {
899 self.seconds as f32 + self.nanoseconds.get() as f32 / Nanosecond::per_t::<f32>(Second)
900 }
901
902 /// Get the number of whole milliseconds in the duration.
903 ///
904 /// ```rust
905 /// # use time::ext::NumericalDuration;
906 /// assert_eq!(1.seconds().whole_milliseconds(), 1_000);
907 /// assert_eq!((-1).seconds().whole_milliseconds(), -1_000);
908 /// assert_eq!(1.milliseconds().whole_milliseconds(), 1);
909 /// assert_eq!((-1).milliseconds().whole_milliseconds(), -1);
910 /// ```
911 #[inline]
912 pub const fn whole_milliseconds(self) -> i128 {
913 self.seconds as i128 * Millisecond::per_t::<i128>(Second)
914 + self.nanoseconds.get() as i128 / Nanosecond::per_t::<i128>(Millisecond)
915 }
916
917 /// Get the number of milliseconds past the number of whole seconds.
918 ///
919 /// Always in the range `-999..=999`.
920 ///
921 /// ```rust
922 /// # use time::ext::NumericalDuration;
923 /// assert_eq!(1.4.seconds().subsec_milliseconds(), 400);
924 /// assert_eq!((-1.4).seconds().subsec_milliseconds(), -400);
925 /// ```
926 #[inline]
927 pub const fn subsec_milliseconds(self) -> i16 {
928 (self.nanoseconds.get() / Nanosecond::per_t::<i32>(Millisecond)) as i16
929 }
930
931 /// Get the number of whole microseconds in the duration.
932 ///
933 /// ```rust
934 /// # use time::ext::NumericalDuration;
935 /// assert_eq!(1.milliseconds().whole_microseconds(), 1_000);
936 /// assert_eq!((-1).milliseconds().whole_microseconds(), -1_000);
937 /// assert_eq!(1.microseconds().whole_microseconds(), 1);
938 /// assert_eq!((-1).microseconds().whole_microseconds(), -1);
939 /// ```
940 #[inline]
941 pub const fn whole_microseconds(self) -> i128 {
942 self.seconds as i128 * Microsecond::per_t::<i128>(Second)
943 + self.nanoseconds.get() as i128 / Nanosecond::per_t::<i128>(Microsecond)
944 }
945
946 /// Get the number of microseconds past the number of whole seconds.
947 ///
948 /// Always in the range `-999_999..=999_999`.
949 ///
950 /// ```rust
951 /// # use time::ext::NumericalDuration;
952 /// assert_eq!(1.0004.seconds().subsec_microseconds(), 400);
953 /// assert_eq!((-1.0004).seconds().subsec_microseconds(), -400);
954 /// ```
955 #[inline]
956 pub const fn subsec_microseconds(self) -> i32 {
957 self.nanoseconds.get() / Nanosecond::per_t::<i32>(Microsecond)
958 }
959
960 /// Get the number of nanoseconds in the duration.
961 ///
962 /// ```rust
963 /// # use time::ext::NumericalDuration;
964 /// assert_eq!(1.microseconds().whole_nanoseconds(), 1_000);
965 /// assert_eq!((-1).microseconds().whole_nanoseconds(), -1_000);
966 /// assert_eq!(1.nanoseconds().whole_nanoseconds(), 1);
967 /// assert_eq!((-1).nanoseconds().whole_nanoseconds(), -1);
968 /// ```
969 #[inline]
970 pub const fn whole_nanoseconds(self) -> i128 {
971 self.seconds as i128 * Nanosecond::per_t::<i128>(Second) + self.nanoseconds.get() as i128
972 }
973
974 /// Get the number of nanoseconds past the number of whole seconds.
975 ///
976 /// The returned value will always be in the range `-999_999_999..=999_999_999`.
977 ///
978 /// ```rust
979 /// # use time::ext::NumericalDuration;
980 /// assert_eq!(1.000_000_400.seconds().subsec_nanoseconds(), 400);
981 /// assert_eq!((-1.000_000_400).seconds().subsec_nanoseconds(), -400);
982 /// ```
983 #[inline]
984 pub const fn subsec_nanoseconds(self) -> i32 {
985 self.nanoseconds.get()
986 }
987
988 /// Get the number of nanoseconds past the number of whole seconds.
989 #[cfg(feature = "quickcheck")]
990 #[inline]
991 pub(crate) const fn subsec_nanoseconds_ranged(self) -> Nanoseconds {
992 self.nanoseconds
993 }
994
995 /// Computes `self + rhs`, returning `None` if an overflow occurred.
996 ///
997 /// ```rust
998 /// # use time::{Duration, ext::NumericalDuration};
999 /// assert_eq!(5.seconds().checked_add(5.seconds()), Some(10.seconds()));
1000 /// assert_eq!(Duration::MAX.checked_add(1.nanoseconds()), None);
1001 /// assert_eq!((-5).seconds().checked_add(5.seconds()), Some(0.seconds()));
1002 /// ```
1003 #[inline]
1004 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
1005 let mut seconds = const_try_opt!(self.seconds.checked_add(rhs.seconds));
1006 let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
1007
1008 if nanoseconds >= Nanosecond::per_t(Second) || seconds < 0 && nanoseconds > 0 {
1009 nanoseconds -= Nanosecond::per_t::<i32>(Second);
1010 seconds = const_try_opt!(seconds.checked_add(1));
1011 } else if nanoseconds <= -Nanosecond::per_t::<i32>(Second) || seconds > 0 && nanoseconds < 0
1012 {
1013 nanoseconds += Nanosecond::per_t::<i32>(Second);
1014 seconds = const_try_opt!(seconds.checked_sub(1));
1015 }
1016
1017 // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
1018 unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
1019 }
1020
1021 /// Computes `self - rhs`, returning `None` if an overflow occurred.
1022 ///
1023 /// ```rust
1024 /// # use time::{Duration, ext::NumericalDuration};
1025 /// assert_eq!(5.seconds().checked_sub(5.seconds()), Some(Duration::ZERO));
1026 /// assert_eq!(Duration::MIN.checked_sub(1.nanoseconds()), None);
1027 /// assert_eq!(5.seconds().checked_sub(10.seconds()), Some((-5).seconds()));
1028 /// ```
1029 #[inline]
1030 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
1031 let mut seconds = const_try_opt!(self.seconds.checked_sub(rhs.seconds));
1032 let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
1033
1034 if nanoseconds >= Nanosecond::per_t(Second) || seconds < 0 && nanoseconds > 0 {
1035 nanoseconds -= Nanosecond::per_t::<i32>(Second);
1036 seconds = const_try_opt!(seconds.checked_add(1));
1037 } else if nanoseconds <= -Nanosecond::per_t::<i32>(Second) || seconds > 0 && nanoseconds < 0
1038 {
1039 nanoseconds += Nanosecond::per_t::<i32>(Second);
1040 seconds = const_try_opt!(seconds.checked_sub(1));
1041 }
1042
1043 // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
1044 unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
1045 }
1046
1047 /// Computes `self * rhs`, returning `None` if an overflow occurred.
1048 ///
1049 /// ```rust
1050 /// # use time::{Duration, ext::NumericalDuration};
1051 /// assert_eq!(5.seconds().checked_mul(2), Some(10.seconds()));
1052 /// assert_eq!(5.seconds().checked_mul(-2), Some((-10).seconds()));
1053 /// assert_eq!(5.seconds().checked_mul(0), Some(0.seconds()));
1054 /// assert_eq!(Duration::MAX.checked_mul(2), None);
1055 /// assert_eq!(Duration::MIN.checked_mul(2), None);
1056 /// ```
1057 #[inline]
1058 pub const fn checked_mul(self, rhs: i32) -> Option<Self> {
1059 // Multiply nanoseconds as i64, because it cannot overflow that way.
1060 let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
1061 let extra_secs = total_nanos / Nanosecond::per_t::<i64>(Second);
1062 let nanoseconds = (total_nanos % Nanosecond::per_t::<i64>(Second)) as i32;
1063 let seconds = const_try_opt!(
1064 const_try_opt!(self.seconds.checked_mul(rhs as i64)).checked_add(extra_secs)
1065 );
1066
1067 // Safety: `nanoseconds` is guaranteed to be in range because of the modulus above.
1068 unsafe { Some(Self::new_unchecked(seconds, nanoseconds)) }
1069 }
1070
1071 /// Computes `self / rhs`, returning `None` if `rhs == 0` or if the result would overflow.
1072 ///
1073 /// ```rust
1074 /// # use time::ext::NumericalDuration;
1075 /// assert_eq!(10.seconds().checked_div(2), Some(5.seconds()));
1076 /// assert_eq!(10.seconds().checked_div(-2), Some((-5).seconds()));
1077 /// assert_eq!(1.seconds().checked_div(0), None);
1078 /// ```
1079 #[inline]
1080 pub const fn checked_div(self, rhs: i32) -> Option<Self> {
1081 let (secs, extra_secs) = (
1082 const_try_opt!(self.seconds.checked_div(rhs as i64)),
1083 self.seconds % (rhs as i64),
1084 );
1085 let (mut nanos, extra_nanos) = (self.nanoseconds.get() / rhs, self.nanoseconds.get() % rhs);
1086 nanos += ((extra_secs * (Nanosecond::per_t::<i64>(Second)) + extra_nanos as i64)
1087 / (rhs as i64)) as i32;
1088
1089 // Safety: `nanoseconds` is in range.
1090 unsafe { Some(Self::new_unchecked(secs, nanos)) }
1091 }
1092
1093 /// Computes `-self`, returning `None` if the result would overflow.
1094 ///
1095 /// ```rust
1096 /// # use time::ext::NumericalDuration;
1097 /// # use time::Duration;
1098 /// assert_eq!(5.seconds().checked_neg(), Some((-5).seconds()));
1099 /// assert_eq!(Duration::MIN.checked_neg(), None);
1100 /// ```
1101 #[inline]
1102 pub const fn checked_neg(self) -> Option<Self> {
1103 if self.seconds == i64::MIN {
1104 None
1105 } else {
1106 Some(Self::new_ranged_unchecked(
1107 -self.seconds,
1108 self.nanoseconds.neg(),
1109 ))
1110 }
1111 }
1112
1113 /// Computes `self + rhs`, saturating if an overflow occurred.
1114 ///
1115 /// ```rust
1116 /// # use time::{Duration, ext::NumericalDuration};
1117 /// assert_eq!(5.seconds().saturating_add(5.seconds()), 10.seconds());
1118 /// assert_eq!(Duration::MAX.saturating_add(1.nanoseconds()), Duration::MAX);
1119 /// assert_eq!(
1120 /// Duration::MIN.saturating_add((-1).nanoseconds()),
1121 /// Duration::MIN
1122 /// );
1123 /// assert_eq!((-5).seconds().saturating_add(5.seconds()), Duration::ZERO);
1124 /// ```
1125 #[inline]
1126 pub const fn saturating_add(self, rhs: Self) -> Self {
1127 let (mut seconds, overflow) = self.seconds.overflowing_add(rhs.seconds);
1128 if overflow {
1129 if self.seconds > 0 {
1130 return Self::MAX;
1131 }
1132 return Self::MIN;
1133 }
1134 let mut nanoseconds = self.nanoseconds.get() + rhs.nanoseconds.get();
1135
1136 if nanoseconds >= Nanosecond::per_t(Second) || seconds < 0 && nanoseconds > 0 {
1137 nanoseconds -= Nanosecond::per_t::<i32>(Second);
1138 seconds = match seconds.checked_add(1) {
1139 Some(seconds) => seconds,
1140 None => return Self::MAX,
1141 };
1142 } else if nanoseconds <= -Nanosecond::per_t::<i32>(Second) || seconds > 0 && nanoseconds < 0
1143 {
1144 nanoseconds += Nanosecond::per_t::<i32>(Second);
1145 seconds = match seconds.checked_sub(1) {
1146 Some(seconds) => seconds,
1147 None => return Self::MIN,
1148 };
1149 }
1150
1151 // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
1152 unsafe { Self::new_unchecked(seconds, nanoseconds) }
1153 }
1154
1155 /// Computes `self - rhs`, saturating if an overflow occurred.
1156 ///
1157 /// ```rust
1158 /// # use time::{Duration, ext::NumericalDuration};
1159 /// assert_eq!(5.seconds().saturating_sub(5.seconds()), Duration::ZERO);
1160 /// assert_eq!(Duration::MIN.saturating_sub(1.nanoseconds()), Duration::MIN);
1161 /// assert_eq!(
1162 /// Duration::MAX.saturating_sub((-1).nanoseconds()),
1163 /// Duration::MAX
1164 /// );
1165 /// assert_eq!(5.seconds().saturating_sub(10.seconds()), (-5).seconds());
1166 /// ```
1167 #[inline]
1168 pub const fn saturating_sub(self, rhs: Self) -> Self {
1169 let (mut seconds, overflow) = self.seconds.overflowing_sub(rhs.seconds);
1170 if overflow {
1171 if self.seconds > 0 {
1172 return Self::MAX;
1173 }
1174 return Self::MIN;
1175 }
1176 let mut nanoseconds = self.nanoseconds.get() - rhs.nanoseconds.get();
1177
1178 if nanoseconds >= Nanosecond::per_t(Second) || seconds < 0 && nanoseconds > 0 {
1179 nanoseconds -= Nanosecond::per_t::<i32>(Second);
1180 seconds = match seconds.checked_add(1) {
1181 Some(seconds) => seconds,
1182 None => return Self::MAX,
1183 };
1184 } else if nanoseconds <= -Nanosecond::per_t::<i32>(Second) || seconds > 0 && nanoseconds < 0
1185 {
1186 nanoseconds += Nanosecond::per_t::<i32>(Second);
1187 seconds = match seconds.checked_sub(1) {
1188 Some(seconds) => seconds,
1189 None => return Self::MIN,
1190 };
1191 }
1192
1193 // Safety: `nanoseconds` is guaranteed to be in range because of the overflow handling.
1194 unsafe { Self::new_unchecked(seconds, nanoseconds) }
1195 }
1196
1197 /// Computes `self * rhs`, saturating if an overflow occurred.
1198 ///
1199 /// ```rust
1200 /// # use time::{Duration, ext::NumericalDuration};
1201 /// assert_eq!(5.seconds().saturating_mul(2), 10.seconds());
1202 /// assert_eq!(5.seconds().saturating_mul(-2), (-10).seconds());
1203 /// assert_eq!(5.seconds().saturating_mul(0), Duration::ZERO);
1204 /// assert_eq!(Duration::MAX.saturating_mul(2), Duration::MAX);
1205 /// assert_eq!(Duration::MIN.saturating_mul(2), Duration::MIN);
1206 /// assert_eq!(Duration::MAX.saturating_mul(-2), Duration::MIN);
1207 /// assert_eq!(Duration::MIN.saturating_mul(-2), Duration::MAX);
1208 /// ```
1209 #[inline]
1210 pub const fn saturating_mul(self, rhs: i32) -> Self {
1211 // Multiply nanoseconds as i64, because it cannot overflow that way.
1212 let total_nanos = self.nanoseconds.get() as i64 * rhs as i64;
1213 let extra_secs = total_nanos / Nanosecond::per_t::<i64>(Second);
1214 let nanoseconds = (total_nanos % Nanosecond::per_t::<i64>(Second)) as i32;
1215 let (seconds, overflow1) = self.seconds.overflowing_mul(rhs as i64);
1216 if overflow1 {
1217 if self.seconds > 0 && rhs > 0 || self.seconds < 0 && rhs < 0 {
1218 return Self::MAX;
1219 }
1220 return Self::MIN;
1221 }
1222 let (seconds, overflow2) = seconds.overflowing_add(extra_secs);
1223 if overflow2 {
1224 if self.seconds > 0 && rhs > 0 {
1225 return Self::MAX;
1226 }
1227 return Self::MIN;
1228 }
1229
1230 // Safety: `nanoseconds` is guaranteed to be in range because of to the modulus above.
1231 unsafe { Self::new_unchecked(seconds, nanoseconds) }
1232 }
1233
1234 /// Runs a closure, returning the duration of time it took to run. The return value of the
1235 /// closure is provided in the second part of the tuple.
1236 #[cfg(feature = "std")]
1237 #[doc(hidden)]
1238 #[inline]
1239 #[track_caller]
1240 #[deprecated(
1241 since = "0.3.32",
1242 note = "extremely limited use case, not intended for benchmarking"
1243 )]
1244 #[expect(deprecated)]
1245 pub fn time_fn<T>(f: impl FnOnce() -> T) -> (Self, T) {
1246 let start = Instant::now();
1247 let return_value = f();
1248 let end = Instant::now();
1249
1250 (end - start, return_value)
1251 }
1252}
1253
1254/// The format returned by this implementation is not stable and must not be relied upon.
1255///
1256/// By default this produces an exact, full-precision printout of the duration.
1257/// For a concise, rounded printout instead, you can use the `.N` format specifier:
1258///
1259/// ```
1260/// # use time::Duration;
1261/// #
1262/// let duration = Duration::new(123456, 789011223);
1263/// println!("{duration:.3}");
1264/// ```
1265///
1266/// For the purposes of this implementation, a day is exactly 24 hours and a minute is exactly 60
1267/// seconds.
1268impl fmt::Display for Duration {
1269 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1270 if self.is_negative() {
1271 f.write_str("-")?;
1272 }
1273
1274 if let Some(_precision) = f.precision() {
1275 // Concise, rounded representation.
1276
1277 if self.is_zero() {
1278 // Write a zero value with the requested precision.
1279 return (0.).fmt(f).and_then(|_| f.write_str("s"));
1280 }
1281
1282 /// Format the first item that produces a value greater than 1 and then break.
1283 macro_rules! item {
1284 ($name:literal, $value:expr) => {
1285 let value = $value;
1286 if value >= 1.0 {
1287 return value.fmt(f).and_then(|_| f.write_str($name));
1288 }
1289 };
1290 }
1291
1292 // Even if this produces a de-normal float, because we're rounding we don't really care.
1293 let seconds = self.unsigned_abs().as_secs_f64();
1294
1295 item!("d", seconds / Second::per_t::<f64>(Day));
1296 item!("h", seconds / Second::per_t::<f64>(Hour));
1297 item!("m", seconds / Second::per_t::<f64>(Minute));
1298 item!("s", seconds);
1299 item!("ms", seconds * Millisecond::per_t::<f64>(Second));
1300 item!("µs", seconds * Microsecond::per_t::<f64>(Second));
1301 item!("ns", seconds * Nanosecond::per_t::<f64>(Second));
1302 } else {
1303 // Precise, but verbose representation.
1304
1305 if self.is_zero() {
1306 return f.write_str("0s");
1307 }
1308
1309 /// Format a single item.
1310 macro_rules! item {
1311 ($name:literal, $value:expr) => {
1312 match $value {
1313 0 => Ok(()),
1314 value => value.fmt(f).and_then(|_| f.write_str($name)),
1315 }
1316 };
1317 }
1318
1319 let seconds = self.seconds.unsigned_abs();
1320 let nanoseconds = self.nanoseconds.get().unsigned_abs();
1321
1322 item!("d", seconds / Second::per_t::<u64>(Day))?;
1323 item!(
1324 "h",
1325 seconds / Second::per_t::<u64>(Hour) % Hour::per_t::<u64>(Day)
1326 )?;
1327 item!(
1328 "m",
1329 seconds / Second::per_t::<u64>(Minute) % Minute::per_t::<u64>(Hour)
1330 )?;
1331 item!("s", seconds % Second::per_t::<u64>(Minute))?;
1332 item!("ms", nanoseconds / Nanosecond::per_t::<u32>(Millisecond))?;
1333 item!(
1334 "µs",
1335 nanoseconds / Nanosecond::per_t::<u32>(Microsecond)
1336 % Microsecond::per_t::<u32>(Millisecond)
1337 )?;
1338 item!("ns", nanoseconds % Nanosecond::per_t::<u32>(Microsecond))?;
1339 }
1340
1341 Ok(())
1342 }
1343}
1344
1345impl TryFrom<StdDuration> for Duration {
1346 type Error = error::ConversionRange;
1347
1348 #[inline]
1349 fn try_from(original: StdDuration) -> Result<Self, error::ConversionRange> {
1350 Ok(Self::new(
1351 original
1352 .as_secs()
1353 .try_into()
1354 .map_err(|_| error::ConversionRange)?,
1355 original.subsec_nanos().cast_signed(),
1356 ))
1357 }
1358}
1359
1360impl TryFrom<Duration> for StdDuration {
1361 type Error = error::ConversionRange;
1362
1363 #[inline]
1364 fn try_from(duration: Duration) -> Result<Self, error::ConversionRange> {
1365 Ok(Self::new(
1366 duration
1367 .seconds
1368 .try_into()
1369 .map_err(|_| error::ConversionRange)?,
1370 duration
1371 .nanoseconds
1372 .get()
1373 .try_into()
1374 .map_err(|_| error::ConversionRange)?,
1375 ))
1376 }
1377}
1378
1379impl Add for Duration {
1380 type Output = Self;
1381
1382 /// # Panics
1383 ///
1384 /// This may panic if an overflow occurs.
1385 #[inline]
1386 #[track_caller]
1387 fn add(self, rhs: Self) -> Self::Output {
1388 self.checked_add(rhs)
1389 .expect("overflow when adding durations")
1390 }
1391}
1392
1393impl Add<StdDuration> for Duration {
1394 type Output = Self;
1395
1396 /// # Panics
1397 ///
1398 /// This may panic if an overflow occurs.
1399 #[inline]
1400 #[track_caller]
1401 fn add(self, std_duration: StdDuration) -> Self::Output {
1402 self + Self::try_from(std_duration)
1403 .expect("overflow converting `std::time::Duration` to `time::Duration`")
1404 }
1405}
1406
1407impl Add<Duration> for StdDuration {
1408 type Output = Duration;
1409
1410 /// # Panics
1411 ///
1412 /// This may panic if an overflow occurs.
1413 #[inline]
1414 #[track_caller]
1415 fn add(self, rhs: Duration) -> Self::Output {
1416 rhs + self
1417 }
1418}
1419
1420impl AddAssign<Self> for Duration {
1421 /// # Panics
1422 ///
1423 /// This may panic if an overflow occurs.
1424 #[inline]
1425 #[track_caller]
1426 fn add_assign(&mut self, rhs: Self) {
1427 *self = *self + rhs;
1428 }
1429}
1430
1431impl AddAssign<StdDuration> for Duration {
1432 /// # Panics
1433 ///
1434 /// This may panic if an overflow occurs.
1435 #[inline]
1436 #[track_caller]
1437 fn add_assign(&mut self, rhs: StdDuration) {
1438 *self = *self + rhs;
1439 }
1440}
1441
1442impl AddAssign<Duration> for StdDuration {
1443 /// # Panics
1444 ///
1445 /// This may panic if the resulting addition cannot be represented.
1446 #[inline]
1447 #[track_caller]
1448 fn add_assign(&mut self, rhs: Duration) {
1449 *self = (*self + rhs).try_into().expect(
1450 "Cannot represent a resulting duration in std. Try `let x = x + rhs;`, which will \
1451 change the type.",
1452 );
1453 }
1454}
1455
1456impl Neg for Duration {
1457 type Output = Self;
1458
1459 /// # Panics
1460 ///
1461 /// This may panic if an overflow occurs.
1462 #[inline]
1463 #[track_caller]
1464 fn neg(self) -> Self::Output {
1465 self.checked_neg().expect("overflow when negating duration")
1466 }
1467}
1468
1469impl Sub for Duration {
1470 type Output = Self;
1471
1472 /// # Panics
1473 ///
1474 /// This may panic if an overflow occurs.
1475 #[inline]
1476 #[track_caller]
1477 fn sub(self, rhs: Self) -> Self::Output {
1478 self.checked_sub(rhs)
1479 .expect("overflow when subtracting durations")
1480 }
1481}
1482
1483impl Sub<StdDuration> for Duration {
1484 type Output = Self;
1485
1486 /// # Panics
1487 ///
1488 /// This may panic if an overflow occurs.
1489 #[inline]
1490 #[track_caller]
1491 fn sub(self, rhs: StdDuration) -> Self::Output {
1492 self - Self::try_from(rhs)
1493 .expect("overflow converting `std::time::Duration` to `time::Duration`")
1494 }
1495}
1496
1497impl Sub<Duration> for StdDuration {
1498 type Output = Duration;
1499
1500 /// # Panics
1501 ///
1502 /// This may panic if an overflow occurs.
1503 #[inline]
1504 #[track_caller]
1505 fn sub(self, rhs: Duration) -> Self::Output {
1506 Duration::try_from(self)
1507 .expect("overflow converting `std::time::Duration` to `time::Duration`")
1508 - rhs
1509 }
1510}
1511
1512impl SubAssign<Self> for Duration {
1513 /// # Panics
1514 ///
1515 /// This may panic if an overflow occurs.
1516 #[inline]
1517 #[track_caller]
1518 fn sub_assign(&mut self, rhs: Self) {
1519 *self = *self - rhs;
1520 }
1521}
1522
1523impl SubAssign<StdDuration> for Duration {
1524 /// # Panics
1525 ///
1526 /// This may panic if an overflow occurs.
1527 #[inline]
1528 #[track_caller]
1529 fn sub_assign(&mut self, rhs: StdDuration) {
1530 *self = *self - rhs;
1531 }
1532}
1533
1534impl SubAssign<Duration> for StdDuration {
1535 /// # Panics
1536 ///
1537 /// This may panic if the resulting subtraction can not be represented.
1538 #[inline]
1539 #[track_caller]
1540 fn sub_assign(&mut self, rhs: Duration) {
1541 *self = (*self - rhs).try_into().expect(
1542 "Cannot represent a resulting duration in std. Try `let x = x - rhs;`, which will \
1543 change the type.",
1544 );
1545 }
1546}
1547
1548/// Given a value and whether it is signed, cast it to the signed version.
1549macro_rules! cast_signed {
1550 (@signed $val:ident) => {
1551 $val
1552 };
1553 (@unsigned $val:ident) => {
1554 $val.cast_signed()
1555 };
1556}
1557
1558/// Implement `Mul` (reflexively), `MulAssign`, `Div`, and `DivAssign` for `Duration` for various
1559/// signed types.
1560macro_rules! duration_mul_div_int {
1561 ($(@$signedness:ident $type:ty),+ $(,)?) => {$(
1562 impl Mul<$type> for Duration {
1563 type Output = Self;
1564
1565 /// # Panics
1566 ///
1567 /// This may panic if an overflow occurs.
1568 #[inline]
1569 #[track_caller]
1570 fn mul(self, rhs: $type) -> Self::Output {
1571 Self::nanoseconds_i128(
1572 self.whole_nanoseconds()
1573 .checked_mul(cast_signed!(@$signedness rhs).extend::<i128>())
1574 .expect("overflow when multiplying duration")
1575 )
1576 }
1577 }
1578
1579 impl Mul<Duration> for $type {
1580 type Output = Duration;
1581
1582 /// # Panics
1583 ///
1584 /// This may panic if an overflow occurs.
1585 #[inline]
1586 #[track_caller]
1587 fn mul(self, rhs: Duration) -> Self::Output {
1588 rhs * self
1589 }
1590 }
1591
1592 impl MulAssign<$type> for Duration {
1593 /// # Panics
1594 ///
1595 /// This may panic if an overflow occurs.
1596 #[inline]
1597 #[track_caller]
1598 fn mul_assign(&mut self, rhs: $type) {
1599 *self = *self * rhs;
1600 }
1601 }
1602
1603 impl Div<$type> for Duration {
1604 type Output = Self;
1605
1606 /// # Panics
1607 ///
1608 /// This may panic if an overflow occurs.
1609 #[inline]
1610 #[track_caller]
1611 fn div(self, rhs: $type) -> Self::Output {
1612 Self::nanoseconds_i128(
1613 self.whole_nanoseconds() / cast_signed!(@$signedness rhs).extend::<i128>()
1614 )
1615 }
1616 }
1617
1618 impl DivAssign<$type> for Duration {
1619 /// # Panics
1620 ///
1621 /// This may panic if an overflow occurs.
1622 #[inline]
1623 #[track_caller]
1624 fn div_assign(&mut self, rhs: $type) {
1625 *self = *self / rhs;
1626 }
1627 }
1628 )+};
1629}
1630
1631duration_mul_div_int! {
1632 @signed i8,
1633 @signed i16,
1634 @signed i32,
1635 @unsigned u8,
1636 @unsigned u16,
1637 @unsigned u32,
1638}
1639
1640impl Mul<f32> for Duration {
1641 type Output = Self;
1642
1643 /// # Panics
1644 ///
1645 /// This may panic if an overflow occurs.
1646 #[inline]
1647 #[track_caller]
1648 fn mul(self, rhs: f32) -> Self::Output {
1649 Self::seconds_f32(self.as_seconds_f32() * rhs)
1650 }
1651}
1652
1653impl Mul<Duration> for f32 {
1654 type Output = Duration;
1655
1656 /// # Panics
1657 ///
1658 /// This may panic if an overflow occurs.
1659 #[inline]
1660 #[track_caller]
1661 fn mul(self, rhs: Duration) -> Self::Output {
1662 rhs * self
1663 }
1664}
1665
1666impl Mul<f64> for Duration {
1667 type Output = Self;
1668
1669 /// # Panics
1670 ///
1671 /// This may panic if an overflow occurs.
1672 #[inline]
1673 #[track_caller]
1674 fn mul(self, rhs: f64) -> Self::Output {
1675 Self::seconds_f64(self.as_seconds_f64() * rhs)
1676 }
1677}
1678
1679impl Mul<Duration> for f64 {
1680 type Output = Duration;
1681
1682 /// # Panics
1683 ///
1684 /// This may panic if an overflow occurs.
1685 #[inline]
1686 #[track_caller]
1687 fn mul(self, rhs: Duration) -> Self::Output {
1688 rhs * self
1689 }
1690}
1691
1692impl MulAssign<f32> for Duration {
1693 /// # Panics
1694 ///
1695 /// This may panic if an overflow occurs.
1696 #[inline]
1697 #[track_caller]
1698 fn mul_assign(&mut self, rhs: f32) {
1699 *self = *self * rhs;
1700 }
1701}
1702
1703impl MulAssign<f64> for Duration {
1704 /// # Panics
1705 ///
1706 /// This may panic if an overflow occurs.
1707 #[inline]
1708 #[track_caller]
1709 fn mul_assign(&mut self, rhs: f64) {
1710 *self = *self * rhs;
1711 }
1712}
1713
1714impl Div<f32> for Duration {
1715 type Output = Self;
1716
1717 /// # Panics
1718 ///
1719 /// This may panic if an overflow occurs.
1720 #[inline]
1721 #[track_caller]
1722 fn div(self, rhs: f32) -> Self::Output {
1723 Self::seconds_f32(self.as_seconds_f32() / rhs)
1724 }
1725}
1726
1727impl Div<f64> for Duration {
1728 type Output = Self;
1729
1730 /// # Panics
1731 ///
1732 /// This may panic if an overflow occurs.
1733 #[inline]
1734 #[track_caller]
1735 fn div(self, rhs: f64) -> Self::Output {
1736 Self::seconds_f64(self.as_seconds_f64() / rhs)
1737 }
1738}
1739
1740impl DivAssign<f32> for Duration {
1741 /// # Panics
1742 ///
1743 /// This may panic if an overflow occurs.
1744 #[inline]
1745 #[track_caller]
1746 fn div_assign(&mut self, rhs: f32) {
1747 *self = *self / rhs;
1748 }
1749}
1750
1751impl DivAssign<f64> for Duration {
1752 /// # Panics
1753 ///
1754 /// This may panic if an overflow occurs.
1755 #[inline]
1756 #[track_caller]
1757 fn div_assign(&mut self, rhs: f64) {
1758 *self = *self / rhs;
1759 }
1760}
1761
1762impl Div for Duration {
1763 type Output = f64;
1764
1765 #[inline]
1766 #[track_caller]
1767 fn div(self, rhs: Self) -> Self::Output {
1768 self.as_seconds_f64() / rhs.as_seconds_f64()
1769 }
1770}
1771
1772impl Div<StdDuration> for Duration {
1773 type Output = f64;
1774
1775 #[inline]
1776 #[track_caller]
1777 fn div(self, rhs: StdDuration) -> Self::Output {
1778 self.as_seconds_f64() / rhs.as_secs_f64()
1779 }
1780}
1781
1782impl Div<Duration> for StdDuration {
1783 type Output = f64;
1784
1785 #[inline]
1786 #[track_caller]
1787 fn div(self, rhs: Duration) -> Self::Output {
1788 self.as_secs_f64() / rhs.as_seconds_f64()
1789 }
1790}
1791
1792impl PartialEq<StdDuration> for Duration {
1793 #[inline]
1794 fn eq(&self, rhs: &StdDuration) -> bool {
1795 Ok(*self) == Self::try_from(*rhs)
1796 }
1797}
1798
1799impl PartialEq<Duration> for StdDuration {
1800 #[inline]
1801 fn eq(&self, rhs: &Duration) -> bool {
1802 rhs == self
1803 }
1804}
1805
1806impl PartialOrd<StdDuration> for Duration {
1807 #[inline]
1808 fn partial_cmp(&self, rhs: &StdDuration) -> Option<Ordering> {
1809 if rhs.as_secs() > i64::MAX.cast_unsigned() {
1810 return Some(Ordering::Less);
1811 }
1812
1813 Some(
1814 self.seconds
1815 .cmp(&rhs.as_secs().cast_signed())
1816 .then_with(|| {
1817 self.nanoseconds
1818 .get()
1819 .cmp(&rhs.subsec_nanos().cast_signed())
1820 }),
1821 )
1822 }
1823}
1824
1825impl PartialOrd<Duration> for StdDuration {
1826 #[inline]
1827 fn partial_cmp(&self, rhs: &Duration) -> Option<Ordering> {
1828 rhs.partial_cmp(self).map(Ordering::reverse)
1829 }
1830}
1831
1832impl Sum for Duration {
1833 #[inline]
1834 fn sum<I>(iter: I) -> Self
1835 where
1836 I: Iterator<Item = Self>,
1837 {
1838 iter.reduce(|a, b| a + b).unwrap_or_default()
1839 }
1840}
1841
1842impl<'a> Sum<&'a Self> for Duration {
1843 #[inline]
1844 fn sum<I>(iter: I) -> Self
1845 where
1846 I: Iterator<Item = &'a Self>,
1847 {
1848 iter.copied().sum()
1849 }
1850}
1851
1852#[cfg(feature = "std")]
1853impl Add<Duration> for SystemTime {
1854 type Output = Self;
1855
1856 /// # Panics
1857 ///
1858 /// This may panic if an overflow occurs.
1859 #[inline]
1860 #[track_caller]
1861 fn add(self, duration: Duration) -> Self::Output {
1862 if duration.is_zero() {
1863 self
1864 } else if duration.is_positive() {
1865 self + duration.unsigned_abs()
1866 } else {
1867 debug_assert!(duration.is_negative());
1868 self - duration.unsigned_abs()
1869 }
1870 }
1871}
1872
1873#[cfg(feature = "std")]
1874impl AddAssign<Duration> for SystemTime {
1875 /// # Panics
1876 ///
1877 /// This may panic if an overflow occurs.
1878 #[inline]
1879 #[track_caller]
1880 fn add_assign(&mut self, rhs: Duration) {
1881 *self = *self + rhs;
1882 }
1883}
1884
1885#[cfg(feature = "std")]
1886impl Sub<Duration> for SystemTime {
1887 type Output = Self;
1888
1889 #[inline]
1890 #[track_caller]
1891 fn sub(self, duration: Duration) -> Self::Output {
1892 if duration.is_zero() {
1893 self
1894 } else if duration.is_positive() {
1895 self - duration.unsigned_abs()
1896 } else {
1897 debug_assert!(duration.is_negative());
1898 self + duration.unsigned_abs()
1899 }
1900 }
1901}
1902
1903#[cfg(feature = "std")]
1904impl SubAssign<Duration> for SystemTime {
1905 /// # Panics
1906 ///
1907 /// This may panic if an overflow occurs.
1908 #[inline]
1909 #[track_caller]
1910 fn sub_assign(&mut self, rhs: Duration) {
1911 *self = *self - rhs;
1912 }
1913}