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