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