cap_primitives/time/
system_time.rs

1use crate::time::{Duration, SystemTimeError};
2use std::ops::{Add, AddAssign, Sub, SubAssign};
3use std::{fmt, time};
4
5/// A measurement of the system clock, useful for talking to external entities
6/// like the file system or other processes.
7///
8/// This corresponds to [`std::time::SystemTime`].
9///
10/// This `SystemTime` has no `now`, `elapsed` methods. To obtain the current
11/// time or measure the duration to the current time, first obtain a
12/// [`SystemClock`], and then call [`SystemClock::now`] or
13/// [`SystemClock::elapsed`] instead. The `UNIX_EPOCH` constant is at
14/// [`SystemClock::UNIX_EPOCH`].
15///
16/// Similar to the [`filetime` crate], when
17/// `RUSTFLAGS=--cfg emulate_second_only_system` is set, `SystemTime` will
18/// round times from the operating system down to the second. This emulates
19/// the behavior of some file systems, mostly
20/// [HFS], allowing debugging on other hardware.
21///
22/// [`SystemClock`]: crate::time::SystemClock
23/// [`SystemClock::now`]: crate::time::SystemClock::now
24/// [`SystemClock::elapsed`]: crate::time::SystemClock::elapsed
25/// [`SystemClock::UNIX_EPOCH`]: crate::time::SystemClock::UNIX_EPOCH
26/// [`filetime` crate]: https://crates.io/crates/filetime
27/// [HFS]: https://en.wikipedia.org/wiki/HFS_Plus
28#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd)]
29pub struct SystemTime {
30    pub(crate) std: time::SystemTime,
31}
32
33impl SystemTime {
34    /// Constructs a new instance of `Self` from the given
35    /// [`std::time::SystemTime`].
36    // TODO: Make this a `const fn` once `time::Duration::checked_add` is a `const fn`.
37    #[inline]
38    pub fn from_std(std: time::SystemTime) -> Self {
39        if cfg!(emulate_second_only_system) {
40            match std.duration_since(time::SystemTime::UNIX_EPOCH) {
41                Ok(duration) => {
42                    let secs = time::Duration::from_secs(duration.as_secs());
43                    Self {
44                        std: time::SystemTime::UNIX_EPOCH.checked_add(secs).unwrap(),
45                    }
46                }
47                Err(_) => {
48                    let duration = time::SystemTime::UNIX_EPOCH.duration_since(std).unwrap();
49                    let secs = time::Duration::from_secs(duration.as_secs());
50                    Self {
51                        std: time::SystemTime::UNIX_EPOCH.checked_sub(secs).unwrap(),
52                    }
53                }
54            }
55        } else {
56            Self { std }
57        }
58    }
59
60    /// Constructs a new instance of [`std::time::SystemTime`] from the given
61    /// `Self`.
62    #[inline]
63    pub const fn into_std(self) -> time::SystemTime {
64        self.std
65    }
66
67    /// Returns the amount of time elapsed from another instant to this one.
68    ///
69    /// This corresponds to [`std::time::SystemTime::duration_since`].
70    #[inline]
71    pub fn duration_since(&self, earlier: Self) -> Result<Duration, SystemTimeError> {
72        self.std.duration_since(earlier.std)
73    }
74
75    /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be
76    /// represented as `SystemTime` (which means it's inside the bounds of the
77    /// underlying data structure), `None` otherwise.
78    ///
79    /// This corresponds to [`std::time::SystemTime::checked_add`].
80    #[inline]
81    pub fn checked_add(&self, duration: Duration) -> Option<Self> {
82        self.std.checked_add(duration).map(Self::from_std)
83    }
84
85    /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be
86    /// represented as `SystemTime` (which means it's inside the bounds of the
87    /// underlying data structure), `None` otherwise.
88    ///
89    /// This corresponds to [`std::time::SystemTime::checked_sub`].
90    #[inline]
91    pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
92        self.std.checked_sub(duration).map(Self::from_std)
93    }
94}
95
96impl Add<Duration> for SystemTime {
97    type Output = Self;
98
99    /// # Panics
100    ///
101    /// This function may panic if the resulting point in time cannot be
102    /// represented by the underlying data structure. See
103    /// [`SystemTime::checked_add`] for a version without panic.
104    #[inline]
105    fn add(self, dur: Duration) -> Self {
106        self.checked_add(dur)
107            .expect("overflow when adding duration to instant")
108    }
109}
110
111impl AddAssign<Duration> for SystemTime {
112    #[inline]
113    fn add_assign(&mut self, other: Duration) {
114        *self = *self + other;
115    }
116}
117
118impl Sub<Duration> for SystemTime {
119    type Output = Self;
120
121    #[inline]
122    fn sub(self, dur: Duration) -> Self {
123        self.checked_sub(dur)
124            .expect("overflow when subtracting duration from instant")
125    }
126}
127
128impl SubAssign<Duration> for SystemTime {
129    #[inline]
130    fn sub_assign(&mut self, other: Duration) {
131        *self = *self - other;
132    }
133}
134
135impl fmt::Debug for SystemTime {
136    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137        self.std.fmt(f)
138    }
139}