unix_time/
lib.rs

1// Copyright 2020 Quentin De Coninck
2//
3// Distributed under MIT license.
4//! A minimal crate to play with Instant based on UNIX epoch.
5//!
6//! The standard library provides Instant and Duration structures to measure
7//! elapsed time. This is fine for most use cases, but the Instant structure
8//! voluntary hides its implementation to keep its semantics. This crate exposes
9//! its time base to the UNIX Epoch (1st January 1970 at 0:00).
10//!
11//! The exposed API tries to mimic as much as possible the `std::time` one for
12//! the related `Instant` structures, such that passing from these to the ones
13//! of this crate would be as seamless as possible (as it actually uses
14//! `std::time` under the hood).
15//!
16//! This crate should only be used to compute local time. It is thus not
17//! appropriate for timezone computations, playing with dates,...
18
19use std::time::SystemTime;
20use std::time::Duration;
21use std::ops::{Add, AddAssign, Sub, SubAssign};
22use std::fmt;
23
24#[cfg(feature = "serde")]
25use serde::{Deserialize, Serialize};
26
27#[cfg(feature = "rkyv")]
28use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
29
30/// An precise instant relative to the UNIX epoch, with nanosecond precision.
31#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33#[cfg_attr(feature = "rkyv", derive(Archive, RkyvDeserialize, RkyvSerialize))]
34pub struct Instant {
35    secs: u64,
36    nanos: u32,
37}
38
39impl Instant {
40    /// Creates an `Instant` at the specified seconds and nanoseconds after the
41    /// UNIX epoch.
42    ///
43    /// # Examples
44    ///
45    /// ```
46    /// use unix_time::Instant;
47    ///
48    /// let instant = Instant::at(42, 182870024);
49    /// assert_eq!(format!("{:?}", instant), "Instant { secs: 42, nanos: 182870024 }");
50    /// ```
51    pub fn at(secs: u64, nanos: u32) -> Self {
52        Self { secs, nanos }
53    }
54
55    /// Returns an instant corresponding to "now".
56    pub fn now() -> Self {
57        let since_epoch = SystemTime::now()
58            .duration_since(SystemTime::UNIX_EPOCH)
59            .expect("SystemTime before UNIX epoch?!?");
60        Self::at(since_epoch.as_secs(), since_epoch.subsec_nanos())
61    }
62
63    /// Returns the number of _whole_ seconds that spaces `self` from the UNIX
64    /// epoch.
65    ///
66    /// The returned value does not include the fractional (nanosecond) part of
67    /// the duration, which can be obtained using [`subsec_nanos`].
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// use unix_time::Instant;
73    ///
74    /// let duration = Instant::at(5, 730023852);
75    /// assert_eq!(duration.secs(), 5);
76    /// ```
77    ///
78    /// To determine the total number of seconds represented by the `Duration`,
79    /// use `secs` in combination with [`subsec_nanos`]:
80    ///
81    /// ```
82    /// use unix_time::Instant;
83    ///
84    /// let instant = Instant::at(5, 730023852);
85    ///
86    /// assert_eq!(5.730023852,
87    ///            instant.secs() as f64
88    ///            + instant.subsec_nanos() as f64 * 1e-9);
89    /// ```
90    ///
91    /// [`subsec_nanos`]: Instant::subsec_nanos
92    pub fn secs(&self) -> u64 {
93        self.secs
94    }
95
96    /// Returns the fractional part that spaces `self` from the UNIX epoch in
97    /// nanoseconds.
98    ///
99    /// This method does _not_ return the total duration since the UNIX epoch in
100    /// nanoseconds. The returned number always represents a fractional portion
101    /// of a second (i.e., it is less than one billion).
102    ///
103    /// # Examples
104    ///
105    /// ```
106    /// use unix_time::Instant;
107    ///
108    /// let instant = Instant::at(5, 10_000_000);
109    /// assert_eq!(instant.secs(), 5);
110    /// assert_eq!(instant.subsec_nanos(), 10_000_000);
111    /// ```
112    pub fn subsec_nanos(&self) -> u32 {
113        self.nanos
114    }
115
116    /// Returns `Some(t)` where `t` is the time `self + duration` if `t` can be
117    /// represented as `Instant` (which means it's inside the bounds of the
118    /// underlying data structure), `None` otherwise.
119    pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
120        let d: Duration = (*self).into();
121        d.checked_add(duration).map(|x| x.into())
122    }
123
124    /// Returns `Some(t)` where `t` is the time `self - duration` if `t` can be
125    /// represented as `Instant` (which means it's inside the bounds of the
126    /// underlying data structure), `None` otherwise.
127    pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
128        let d: Duration = (*self).into();
129        d.checked_sub(duration).map(|x| x.into())
130    }
131
132    /// Returns the amount of time elapsed from another instant to this one,
133    /// or None if that instant is later than this one.
134    ///
135    /// # Examples
136    ///
137    /// ```no_run
138    /// use unix_time::Instant;
139    /// use std::time::Duration;
140    /// use std::thread::sleep;
141    ///
142    /// let now = Instant::now();
143    /// sleep(Duration::new(1, 0));
144    /// let new_now = Instant::now();
145    /// println!("{:?}", new_now.checked_duration_since(now));
146    /// println!("{:?}", now.checked_duration_since(new_now)); // None
147    /// ```
148    pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
149        let d: Duration = (*self).into();
150        d.checked_sub(earlier.into())
151    }
152
153    /// Returns the amount of time elapsed from another instant to this one.
154    ///
155    /// # Panics
156    ///
157    /// This function will panic if `earlier` is later than `self`.
158    ///
159    /// # Examples
160    ///
161    /// ```no_run
162    /// use std::time::Duration;
163    /// use unix_time::Instant;
164    /// use std::thread::sleep;
165    ///
166    /// let now = Instant::now();
167    /// sleep(Duration::new(1, 0).into());
168    /// let new_now = Instant::now();
169    /// println!("{:?}", new_now.duration_since(now));
170    /// ```
171    pub fn duration_since(&self, earlier: Instant) -> Duration {
172        self.checked_duration_since(earlier).expect("supplied instant is later than self")
173    }
174
175    /// Returns the amount of time elapsed from another instant to this one,
176    /// or zero duration if that instant is later than this one.
177    ///
178    /// # Examples
179    ///
180    /// ```no_run
181    /// use std::time::Duration;
182    /// use unix_time::Instant;
183    /// use std::thread::sleep;
184    ///
185    /// let now = Instant::now();
186    /// sleep(Duration::new(1, 0));
187    /// let new_now = Instant::now();
188    /// println!("{:?}", new_now.saturating_duration_since(now));
189    /// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns
190    /// ```
191    pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
192        self.checked_duration_since(earlier).unwrap_or(Duration::new(0, 0))
193    }
194
195    /// Returns the amount of time elapsed since this instant was created.
196    ///
197    /// # Panics
198    ///
199    /// This function may panic if the current time is earlier than this
200    /// instant, which is something that can happen if an `Instant` is
201    /// produced synthetically.
202    ///
203    /// # Examples
204    ///
205    /// ```no_run
206    /// use std::thread::sleep;
207    /// use std::time::Duration;
208    /// use unix_time::Instant;
209    ///
210    /// let instant = Instant::now();
211    /// let three_secs = Duration::from_secs(3);
212    /// sleep(three_secs);
213    /// assert!(instant.elapsed() >= three_secs);
214    /// ```
215    pub fn elapsed(&self) -> Duration {
216        Instant::now() - *self
217    }
218}
219
220impl From<Instant> for Duration {
221    fn from(i: Instant) -> Duration {
222        Duration::new(i.secs, i.nanos)
223    }
224}
225
226impl From<Duration> for Instant {
227    fn from(d: Duration) -> Instant {
228        Instant::at(d.as_secs(), d.subsec_nanos())
229    }
230}
231
232impl Add<Duration> for Instant {
233    type Output = Instant;
234
235    /// # Panics
236    ///
237    /// This function may panic if the resulting point in time cannot be represented by the
238    /// underlying data structure. See [`Instant::checked_add`] for a version without panic.
239    fn add(self, other: Duration) -> Instant {
240        self.checked_add(other).expect("overflow when adding duration to instant")
241    }
242}
243
244impl AddAssign<Duration> for Instant {
245    fn add_assign(&mut self, other: Duration) {
246        *self = *self + other;
247    }
248}
249
250impl Sub<Duration> for Instant {
251    type Output = Instant;
252
253    fn sub(self, other: Duration) -> Instant {
254        self.checked_sub(other).expect("overflow when subtracting duration from instant")
255    }
256}
257
258impl SubAssign<Duration> for Instant {
259    fn sub_assign(&mut self, other: Duration) {
260        *self = *self - other;
261    }
262}
263
264impl Sub<Instant> for Instant {
265    type Output = Duration;
266
267    fn sub(self, other: Instant) -> Duration {
268        self.duration_since(other)
269    }
270}
271
272impl fmt::Debug for Instant {
273    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
274        write!(f, "Instant {{ secs: {}, nanos: {} }}", self.secs, self.nanos)
275    }
276}