msr_core/
time.rs

1//! Time related types
2
3use std::{
4    fmt,
5    ops::{Add, AddAssign, Deref, DerefMut, Sub, SubAssign},
6    time::{Duration, Instant, SystemTime},
7};
8
9use time::{
10    error::IndeterminateOffset, format_description::well_known::Rfc3339, OffsetDateTime, UtcOffset,
11};
12
13/// A system time with the corresponding instant.
14///
15/// This should only be used for anchoring values of Instant
16/// for conversion into system time.
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct SystemInstant {
19    system_time: SystemTime,
20    instant: Instant,
21}
22
23impl SystemInstant {
24    #[must_use]
25    pub const fn new(system_time: SystemTime, instant: Instant) -> Self {
26        Self {
27            system_time,
28            instant,
29        }
30    }
31
32    #[must_use]
33    pub fn now() -> Self {
34        let system_time = SystemTime::now();
35        // Assumption: The current instant obtained right AFTER receiving
36        // the current system time denotes the same point in time and any
37        // difference between them is negligible.
38        let instant = Instant::now();
39        Self::new(system_time, instant)
40    }
41
42    #[must_use]
43    pub fn system_time(&self) -> SystemTime {
44        self.system_time
45    }
46
47    #[must_use]
48    pub fn instant(&self) -> Instant {
49        self.instant
50    }
51
52    #[must_use]
53    pub fn timestamp_utc(&self) -> Timestamp {
54        TimestampInner::from(self.system_time).into()
55    }
56
57    #[must_use]
58    pub fn checked_duration_since_instant(&self, since_instant: Instant) -> Option<Duration> {
59        self.instant.checked_duration_since(since_instant)
60    }
61
62    #[must_use]
63    pub fn checked_duration_until_instant(&self, until_instant: Instant) -> Option<Duration> {
64        until_instant.checked_duration_since(self.instant)
65    }
66
67    #[must_use]
68    pub fn checked_system_time_for_instant(&self, instant: Instant) -> Option<SystemTime> {
69        if self.instant < instant {
70            self.system_time
71                .checked_add(instant.duration_since(self.instant))
72        } else {
73            self.system_time
74                .checked_sub(self.instant.duration_since(instant))
75        }
76    }
77}
78
79impl Add<Duration> for SystemInstant {
80    type Output = Self;
81
82    fn add(self, rhs: Duration) -> Self {
83        let Self {
84            system_time,
85            instant,
86        } = self;
87        Self::new(system_time + rhs, instant + rhs)
88    }
89}
90
91impl AddAssign<Duration> for SystemInstant {
92    fn add_assign(&mut self, rhs: Duration) {
93        let Self {
94            mut system_time,
95            mut instant,
96        } = self;
97        system_time += rhs;
98        instant += rhs;
99    }
100}
101
102type TimestampInner = OffsetDateTime;
103
104/// A timestamp
105#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
106pub struct Timestamp(TimestampInner);
107
108impl Timestamp {
109    #[must_use]
110    pub const fn new(inner: TimestampInner) -> Self {
111        Self(inner)
112    }
113
114    #[must_use]
115    pub const fn to_inner(self) -> TimestampInner {
116        let Self(inner) = self;
117        inner
118    }
119
120    #[must_use]
121    pub const fn to_utc(self) -> Self {
122        Self(self.to_inner().to_offset(UtcOffset::UTC))
123    }
124
125    /// Current system time with offset
126    ///
127    /// Tries to obtain the current system time with the local time zone
128    /// offset. Returns an UTC timestamp as a fallback if the local time
129    /// zone is unknown or could not be determined.
130    ///
131    /// Prefer to use [`Self::now_utc()`] if the local time zone offset doesn't
132    /// matter.
133    #[must_use]
134    pub fn now() -> Self {
135        TimestampInner::now_local()
136            .unwrap_or_else(|_: IndeterminateOffset| TimestampInner::now_utc())
137            .into()
138    }
139
140    /// Current system time (UTC)
141    #[must_use]
142    pub fn now_utc() -> Self {
143        TimestampInner::now_utc().into()
144    }
145
146    pub fn parse_rfc3339(input: &str) -> Result<Self, time::error::Parse> {
147        TimestampInner::parse(input, &Rfc3339).map(Self::new)
148    }
149
150    pub fn format_rfc3339(&self) -> Result<String, time::error::Format> {
151        self.0.format(&Rfc3339)
152    }
153
154    pub fn format_rfc3339_into<W: std::io::Write>(
155        &self,
156        output: &mut W,
157    ) -> Result<usize, time::error::Format> {
158        self.0.format_into(output, &Rfc3339)
159    }
160}
161
162impl From<TimestampInner> for Timestamp {
163    fn from(inner: TimestampInner) -> Self {
164        Self::new(inner)
165    }
166}
167
168impl From<Timestamp> for TimestampInner {
169    fn from(from: Timestamp) -> Self {
170        from.to_inner()
171    }
172}
173
174impl From<SystemTime> for Timestamp {
175    fn from(system_time: SystemTime) -> Self {
176        Self::new(system_time.into())
177    }
178}
179
180impl From<Timestamp> for SystemTime {
181    fn from(from: Timestamp) -> Self {
182        from.to_inner().into()
183    }
184}
185
186impl AsRef<TimestampInner> for Timestamp {
187    fn as_ref(&self) -> &TimestampInner {
188        &self.0
189    }
190}
191
192impl Deref for Timestamp {
193    type Target = TimestampInner;
194
195    fn deref(&self) -> &TimestampInner {
196        self.as_ref()
197    }
198}
199
200impl DerefMut for Timestamp {
201    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
202        let Self(inner) = self;
203        inner
204    }
205}
206
207impl fmt::Display for Timestamp {
208    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209        self.as_ref().fmt(f)
210    }
211}
212
213#[cfg(feature = "serde")]
214impl serde::Serialize for Timestamp {
215    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
216    where
217        S: serde::Serializer,
218    {
219        time::serde::rfc3339::serialize(self.as_ref(), serializer)
220    }
221}
222
223#[cfg(feature = "serde")]
224impl<'de> serde::Deserialize<'de> for Timestamp {
225    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
226    where
227        D: serde::Deserializer<'de>,
228    {
229        time::serde::rfc3339::deserialize(deserializer).map(Self::new)
230    }
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq)]
234pub enum Interval {
235    Nanos(u32),
236    Micros(u32),
237    Millis(u32),
238    Seconds(u32),
239    Minutes(u32),
240    Hours(u32),
241    Days(u32),
242    Weeks(u32),
243}
244
245impl Interval {
246    fn as_duration(self) -> Duration {
247        match self {
248            Self::Nanos(nanos) => Duration::from_nanos(u64::from(nanos)),
249            Self::Micros(micros) => Duration::from_micros(u64::from(micros)),
250            Self::Millis(millis) => Duration::from_millis(u64::from(millis)),
251            Self::Seconds(secs) => Duration::from_secs(u64::from(secs)),
252            Self::Minutes(mins) => Duration::from_secs(u64::from(mins) * 60),
253            Self::Hours(hrs) => Duration::from_secs(u64::from(hrs) * 60 * 60),
254            Self::Days(days) => Duration::from_secs(u64::from(days) * 60 * 60 * 24),
255            Self::Weeks(weeks) => Duration::from_secs(u64::from(weeks) * 60 * 60 * 24 * 7),
256        }
257    }
258
259    #[must_use]
260    pub fn system_time_before(&self, system_time: SystemTime) -> SystemTime {
261        system_time - self.as_duration()
262    }
263
264    #[must_use]
265    pub fn system_time_after(&self, system_time: SystemTime) -> SystemTime {
266        system_time + self.as_duration()
267    }
268}
269
270impl Add<Interval> for Timestamp {
271    type Output = Timestamp;
272
273    fn add(self, interval: Interval) -> Self::Output {
274        (self.to_inner() + interval.as_duration()).into()
275    }
276}
277
278impl AddAssign<Interval> for Timestamp {
279    fn add_assign(&mut self, interval: Interval) {
280        *self = *self + interval;
281    }
282}
283
284impl Sub<Interval> for Timestamp {
285    type Output = Timestamp;
286
287    fn sub(self, interval: Interval) -> Self::Output {
288        (self.to_inner() - interval.as_duration()).into()
289    }
290}
291
292impl SubAssign<Interval> for Timestamp {
293    fn sub_assign(&mut self, interval: Interval) {
294        *self = *self - interval;
295    }
296}