crux_time/protocol/
instant.rs

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