time/ext/systemtime.rs
1use std::time::SystemTime;
2
3use crate::Duration;
4
5/// Sealed trait to prevent downstream implementations.
6mod sealed {
7 /// A trait that cannot be implemented by downstream users.
8 pub trait Sealed: Sized {}
9 impl Sealed for std::time::SystemTime {}
10}
11
12/// An extension trait for [`std::time::SystemTime`] that adds methods for
13/// [`time::Duration`](Duration)s.
14pub trait SystemTimeExt: sealed::Sealed {
15 /// Adds the given [`Duration`] to the [`SystemTime`], returning `None` is the result cannot be
16 /// represented by the underlying data structure.
17 fn checked_add_signed(&self, duration: Duration) -> Option<Self>;
18
19 /// Subtracts the given [`Duration`] from the [`SystemTime`], returning `None` is the result
20 /// cannot be represented by the underlying data structure.
21 fn checked_sub_signed(&self, duration: Duration) -> Option<Self>;
22
23 /// Returns the amount of time elapsed from another [`SystemTime`] to this one. This will be
24 /// negative if `earlier` is later than `self.`
25 ///
26 /// If the duration cannot be stored by [`Duration`], the value will be saturated to
27 /// [`Duration::MIN`] or [`Duration::MAX`] as appropriate.
28 ///
29 /// # Example
30 ///
31 /// ```rust
32 /// # use std::time::SystemTime;
33 /// # use time::ext::{NumericalDuration, SystemTimeExt};
34 /// let epoch = SystemTime::UNIX_EPOCH;
35 /// let other = epoch + 1.seconds();
36 /// assert_eq!(other.signed_duration_since(epoch), 1.seconds());
37 /// assert_eq!(epoch.signed_duration_since(other), (-1).seconds());
38 /// ```
39 fn signed_duration_since(&self, earlier: Self) -> Duration;
40}
41
42impl SystemTimeExt for SystemTime {
43 #[inline]
44 fn checked_add_signed(&self, duration: Duration) -> Option<Self> {
45 if duration.is_positive() {
46 self.checked_add(duration.unsigned_abs())
47 } else if duration.is_negative() {
48 self.checked_sub(duration.unsigned_abs())
49 } else {
50 Some(*self)
51 }
52 }
53
54 #[inline]
55 fn checked_sub_signed(&self, duration: Duration) -> Option<Self> {
56 if duration.is_positive() {
57 self.checked_sub(duration.unsigned_abs())
58 } else if duration.is_negative() {
59 self.checked_add(duration.unsigned_abs())
60 } else {
61 Some(*self)
62 }
63 }
64
65 #[inline]
66 fn signed_duration_since(&self, earlier: Self) -> Duration {
67 match self.duration_since(earlier) {
68 Ok(duration) => duration.try_into().unwrap_or(Duration::MAX),
69 Err(err) => {
70 let seconds = match i64::try_from(err.duration().as_secs()) {
71 Ok(seconds) => -seconds,
72 Err(_) => return Duration::MIN,
73 };
74 let nanoseconds = -err.duration().subsec_nanos().cast_signed();
75
76 // Safety: `nanoseconds` is guaranteed to be between -999_999_999 and 0
77 // inclusive.
78 unsafe { Duration::new_unchecked(seconds, nanoseconds) }
79 }
80 }
81 }
82}