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/// An `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    /// Return a `UnixInstant` that represents the current moment in time.
37    pub fn now() -> Self {
38        crate::sys::realtime::precise()
39    }
40
41    /// Return the elapsed time, in nanoseconds, since the original timestamp.
42    pub fn elapsed(&self) -> Duration {
43        Self::now() - *self
44    }
45
46    /// Return the elapsed duration, in nanoseconds, from some earlier timestamp
47    /// until this timestamp.
48    pub fn duration_since(&self, earlier: Self) -> Duration {
49        *self - earlier
50    }
51
52    pub fn checked_duration_since(&self, earlier: Self) -> Option<Duration> {
53        self.ns.checked_sub(earlier.ns).map(|ns| Duration { ns })
54    }
55
56    pub fn checked_sub(&self, duration: Duration) -> Option<Self> {
57        self.ns.checked_sub(duration.ns).map(|ns| Self { ns })
58    }
59}
60
61impl Add<Duration> for UnixInstant {
62    type Output = UnixInstant;
63
64    fn add(self, rhs: Duration) -> Self::Output {
65        UnixInstant {
66            ns: self.ns + rhs.ns,
67        }
68    }
69}
70
71impl Add<core::time::Duration> for UnixInstant {
72    type Output = UnixInstant;
73
74    fn add(self, rhs: core::time::Duration) -> Self::Output {
75        UnixInstant {
76            ns: self.ns + rhs.as_nanos() as u64,
77        }
78    }
79}
80
81impl Sub<UnixInstant> for UnixInstant {
82    type Output = Duration;
83
84    fn sub(self, rhs: UnixInstant) -> Self::Output {
85        Duration {
86            ns: self.ns - rhs.ns,
87        }
88    }
89}
90
91impl AddAssign<Duration> for UnixInstant {
92    fn add_assign(&mut self, rhs: Duration) {
93        self.ns += rhs.ns;
94    }
95}
96
97impl Sub<Duration> for UnixInstant {
98    type Output = UnixInstant;
99
100    fn sub(self, rhs: Duration) -> Self::Output {
101        UnixInstant {
102            ns: self.ns - rhs.ns,
103        }
104    }
105}
106
107impl SubAssign<Duration> for UnixInstant {
108    fn sub_assign(&mut self, rhs: Duration) {
109        self.ns -= rhs.ns;
110    }
111}
112
113impl AddAssign<core::time::Duration> for UnixInstant {
114    fn add_assign(&mut self, rhs: core::time::Duration) {
115        self.ns += rhs.as_nanos() as u64;
116    }
117}
118
119impl Sub<core::time::Duration> for UnixInstant {
120    type Output = UnixInstant;
121
122    fn sub(self, rhs: core::time::Duration) -> Self::Output {
123        UnixInstant {
124            ns: self.ns - rhs.as_nanos() as u64,
125        }
126    }
127}
128
129impl SubAssign<core::time::Duration> for UnixInstant {
130    fn sub_assign(&mut self, rhs: core::time::Duration) {
131        self.ns -= rhs.as_nanos() as u64;
132    }
133}
134
135impl From<crate::coarse::UnixInstant> for UnixInstant {
136    fn from(other: crate::coarse::UnixInstant) -> Self {
137        Self {
138            ns: other.secs as u64 * super::Duration::NANOSECOND.as_nanos(),
139        }
140    }
141}
142
143pub struct TryFromError {
144    kind: TryFromErrorKind,
145}
146
147enum TryFromErrorKind {
148    Overflow,
149    BeforeEpoch,
150}
151
152impl TryFromError {
153    const fn description(&self) -> &'static str {
154        match self.kind {
155            TryFromErrorKind::Overflow => "can not convert to UnixInstant: value is too big",
156            TryFromErrorKind::BeforeEpoch => {
157                "can not convert to UnixInstant: value is before unix epoch"
158            }
159        }
160    }
161}
162
163impl core::fmt::Display for TryFromError {
164    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
165        self.description().fmt(f)
166    }
167}
168
169impl TryFrom<std::time::SystemTime> for UnixInstant {
170    type Error = TryFromError;
171
172    fn try_from(other: std::time::SystemTime) -> Result<Self, Self::Error> {
173        let other = other
174            .duration_since(std::time::SystemTime::UNIX_EPOCH)
175            .map_err(|_| TryFromError {
176                kind: TryFromErrorKind::BeforeEpoch,
177            })?
178            .as_nanos();
179        if other > u64::MAX as u128 {
180            Err(TryFromError {
181                kind: TryFromErrorKind::Overflow,
182            })
183        } else {
184            Ok(Self { ns: other as u64 })
185        }
186    }
187}