Skip to main content

clocksource/precise/
unix_instant.rs

1use core::ops::{Add, AddAssign, Sub, SubAssign};
2
3use super::Duration;
4
5/// A measurement of the system clock in nanoseconds.
6///
7/// A `precise::UnixInstant` represents a moment in time and is taken from the
8/// system realtime clock. Unlike `std::time::SystemTime` the internal
9/// representation uses only nanoseconds in a u64 field to hold the clock
10/// reading.
11///
12/// This will wrap on Jul 21 2554 (UTC) and cannot represent times before the
13/// UNIX epoch on Jan 01 1970 (UTC).
14///
15/// As with `std::time::SystemTime`, `UnixInstant`s are not guaranteed to be
16/// steady. They are taken from a clock which is subject to phase and frequency
17/// adjustments. This means that they may jump forward or backwards and speed up
18/// or slow down.
19///
20/// This type is useful for representing moments in time across restarts and
21/// across systems as long as the clocks are reasonably synchronized to a common
22/// reference.
23///
24/// The size of a `precise::UnixInstant` is always the same as a `u64`.
25#[repr(transparent)]
26#[derive(Copy, Clone, Default, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
27pub struct UnixInstant {
28    pub(crate) ns: u64,
29}
30
31impl UnixInstant {
32    /// An anchor in time defined as `1970-01-01T00:00:00.000Z`. It can be used
33    /// to create new `UnixInstant`s or learn about other `UnixInstant`s.
34    pub const EPOCH: UnixInstant = UnixInstant { ns: 0 };
35
36    /// Create a new `UnixInstant` from a whole number of nanoseconds since
37    /// the UNIX epoch.
38    pub const fn from_nanos(ns: u64) -> Self {
39        Self { ns }
40    }
41
42    /// Returns the whole number of nanoseconds since the UNIX epoch.
43    pub const fn as_nanos(&self) -> u64 {
44        self.ns
45    }
46
47    /// Return a `UnixInstant` that represents the current moment in time.
48    pub fn now() -> Self {
49        crate::sys::realtime::precise()
50    }
51
52    /// Return the elapsed time, in nanoseconds, since the original timestamp.
53    pub fn elapsed(&self) -> Duration {
54        Self::now() - *self
55    }
56
57    /// Return the elapsed duration, in nanoseconds, from some earlier timestamp
58    /// until this timestamp.
59    pub fn duration_since(&self, earlier: Self) -> Duration {
60        *self - earlier
61    }
62
63    /// Returns the duration since `earlier`, or `None` if `earlier` is after `self`.
64    pub fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
65        self.ns.checked_sub(earlier.ns).map(|ns| Duration { ns })
66    }
67
68    /// Subtracts a duration, returning `None` on underflow.
69    pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
70        self.ns.checked_sub(duration.ns).map(|ns| Self { ns })
71    }
72
73    /// Returns the whole number of seconds since the Unix epoch.
74    pub const fn as_secs(&self) -> u64 {
75        self.ns / 1_000_000_000
76    }
77
78    /// Adds a duration, returning `None` on overflow.
79    pub fn checked_add(&self, duration: Duration) -> Option<Self> {
80        self.ns
81            .checked_add(duration.as_nanos())
82            .map(|ns| Self { ns })
83    }
84}
85
86impl Add<Duration> for UnixInstant {
87    type Output = UnixInstant;
88
89    fn add(self, rhs: Duration) -> Self::Output {
90        UnixInstant {
91            ns: self.ns + rhs.ns,
92        }
93    }
94}
95
96impl Add<core::time::Duration> for UnixInstant {
97    type Output = UnixInstant;
98
99    fn add(self, rhs: core::time::Duration) -> Self::Output {
100        UnixInstant {
101            ns: self.ns + rhs.as_nanos() as u64,
102        }
103    }
104}
105
106impl Sub<UnixInstant> for UnixInstant {
107    type Output = Duration;
108
109    fn sub(self, rhs: UnixInstant) -> Self::Output {
110        Duration {
111            ns: self.ns - rhs.ns,
112        }
113    }
114}
115
116impl AddAssign<Duration> for UnixInstant {
117    fn add_assign(&mut self, rhs: Duration) {
118        self.ns += rhs.ns;
119    }
120}
121
122impl Sub<Duration> for UnixInstant {
123    type Output = UnixInstant;
124
125    fn sub(self, rhs: Duration) -> Self::Output {
126        UnixInstant {
127            ns: self.ns - rhs.ns,
128        }
129    }
130}
131
132impl SubAssign<Duration> for UnixInstant {
133    fn sub_assign(&mut self, rhs: Duration) {
134        self.ns -= rhs.ns;
135    }
136}
137
138impl AddAssign<core::time::Duration> for UnixInstant {
139    fn add_assign(&mut self, rhs: core::time::Duration) {
140        self.ns += rhs.as_nanos() as u64;
141    }
142}
143
144impl Sub<core::time::Duration> for UnixInstant {
145    type Output = UnixInstant;
146
147    fn sub(self, rhs: core::time::Duration) -> Self::Output {
148        UnixInstant {
149            ns: self.ns - rhs.as_nanos() as u64,
150        }
151    }
152}
153
154impl SubAssign<core::time::Duration> for UnixInstant {
155    fn sub_assign(&mut self, rhs: core::time::Duration) {
156        self.ns -= rhs.as_nanos() as u64;
157    }
158}
159
160impl From<crate::coarse::UnixInstant> for UnixInstant {
161    fn from(other: crate::coarse::UnixInstant) -> Self {
162        Self {
163            ns: other.secs as u64 * super::Duration::SECOND.as_nanos(),
164        }
165    }
166}
167
168#[derive(Debug)]
169pub struct TryFromError {
170    kind: TryFromErrorKind,
171}
172
173#[derive(Debug)]
174enum TryFromErrorKind {
175    Overflow,
176    BeforeEpoch,
177}
178
179impl TryFromError {
180    const fn description(&self) -> &'static str {
181        match self.kind {
182            TryFromErrorKind::Overflow => "can not convert to UnixInstant: value is too big",
183            TryFromErrorKind::BeforeEpoch => {
184                "can not convert to UnixInstant: value is before unix epoch"
185            }
186        }
187    }
188}
189
190impl core::fmt::Display for TryFromError {
191    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
192        self.description().fmt(f)
193    }
194}
195
196impl std::error::Error for TryFromError {}
197
198impl TryFrom<std::time::SystemTime> for UnixInstant {
199    type Error = TryFromError;
200
201    fn try_from(other: std::time::SystemTime) -> Result<Self, Self::Error> {
202        let other = other
203            .duration_since(std::time::SystemTime::UNIX_EPOCH)
204            .map_err(|_| TryFromError {
205                kind: TryFromErrorKind::BeforeEpoch,
206            })?
207            .as_nanos();
208        if other > u64::MAX as u128 {
209            Err(TryFromError {
210                kind: TryFromErrorKind::Overflow,
211            })
212        } else {
213            Ok(Self { ns: other as u64 })
214        }
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    #[test]
221    fn from_coarse_unix_instant() {
222        let coarse = crate::coarse::UnixInstant::from_secs(5);
223        let precise = super::UnixInstant::from(coarse);
224        assert_eq!(precise.as_nanos(), 5_000_000_000);
225    }
226}