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