Skip to main content

crux_time/protocol/
instant.rs

1use std::time::SystemTime;
2
3use facet::Facet;
4use serde::{Deserialize, Serialize};
5
6/// The number of nanoseconds in seconds.
7const NANOS_PER_SEC: u32 = 1_000_000_000;
8
9/// Represents a point in time (UTC):
10///
11/// - seconds: number of seconds since the Unix epoch (1970-01-01T00:00:00Z)
12/// - nanos: number of nanoseconds since the last second
13#[derive(Facet, Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct Instant {
16    pub(crate) seconds: u64,
17    pub(crate) nanos: u32,
18}
19
20impl Instant {
21    /// Create a new `Instant` from the given number of seconds and nanoseconds.
22    ///
23    /// - seconds: number of seconds since the Unix epoch (1970-01-01T00:00:00Z)
24    /// - nanos: number of nanoseconds since the last second
25    ///
26    /// # Panics
27    /// if the number of seconds would overflow when converted to nanoseconds.
28    #[must_use]
29    pub fn new(seconds: u64, nanos: u32) -> Self {
30        assert!(
31            nanos < NANOS_PER_SEC,
32            "nanos must be less than {NANOS_PER_SEC}"
33        );
34        Self { seconds, nanos }
35    }
36}
37
38impl From<SystemTime> for Instant {
39    fn from(time: SystemTime) -> Self {
40        let duration = time.duration_since(SystemTime::UNIX_EPOCH).unwrap();
41        let seconds = duration.as_secs();
42        let nanos = duration.subsec_nanos();
43        Self { seconds, nanos }
44    }
45}
46
47impl From<Instant> for SystemTime {
48    fn from(time: Instant) -> Self {
49        SystemTime::UNIX_EPOCH + std::time::Duration::new(time.seconds, time.nanos)
50    }
51}
52
53#[cfg(test)]
54mod test {
55    use super::*;
56
57    #[test]
58    fn new_instant() {
59        let instant = Instant::new(1_000_000_000, 10);
60        assert_eq!(instant.seconds, 1_000_000_000);
61        assert_eq!(instant.nanos, 10);
62    }
63
64    #[test]
65    #[should_panic = "nanos must be less than 1000000000"]
66    fn new_instant_invalid_nanos() {
67        let _ = Instant::new(1_000_000_000, 1_000_000_000);
68    }
69
70    #[test]
71    fn instant_to_std() {
72        let actual: SystemTime = Instant::new(1_000_000_000, 10).into();
73        let expected = SystemTime::UNIX_EPOCH + std::time::Duration::new(1_000_000_000, 10);
74        assert_eq!(actual, expected);
75    }
76
77    #[test]
78    fn std_to_instant() {
79        let sys_time = SystemTime::UNIX_EPOCH + std::time::Duration::new(1_000_000_000, 10);
80        let actual: Instant = sys_time.into();
81        let expected = Instant::new(1_000_000_000, 10);
82        assert_eq!(actual, expected);
83    }
84}