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