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}