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
19/// Create a new `Instant` from the given number of seconds and nanoseconds.
20///
21/// - seconds: number of seconds since the Unix epoch (1970-01-01T00:00:00Z)
22/// - nanos: number of nanoseconds since the last second
23///
24/// Panics if the number of seconds
25/// would overflow when converted to nanoseconds.
26impl Instant {
27    pub fn new(seconds: u64, nanos: u32) -> Self {
28        if nanos >= NANOS_PER_SEC {
29            panic!("nanos must be less than {}", NANOS_PER_SEC);
30        }
31        Self { seconds, nanos }
32    }
33}
34
35impl From<SystemTime> for Instant {
36    fn from(time: SystemTime) -> Self {
37        let duration = time.duration_since(SystemTime::UNIX_EPOCH).unwrap();
38        let seconds = duration.as_secs();
39        let nanos = duration.subsec_nanos();
40        Self { seconds, nanos }
41    }
42}
43
44impl From<Instant> for SystemTime {
45    fn from(time: Instant) -> Self {
46        SystemTime::UNIX_EPOCH + std::time::Duration::new(time.seconds, time.nanos)
47    }
48}
49
50#[cfg(test)]
51mod test {
52    use super::*;
53
54    #[test]
55    fn new_instant() {
56        let instant = Instant::new(1_000_000_000, 10);
57        assert_eq!(instant.seconds, 1_000_000_000);
58        assert_eq!(instant.nanos, 10);
59    }
60
61    #[test]
62    #[should_panic]
63    fn new_instant_invalid_nanos() {
64        Instant::new(1_000_000_000, 1_000_000_000);
65    }
66
67    #[test]
68    fn instant_to_std() {
69        let actual: SystemTime = Instant::new(1_000_000_000, 10).into();
70        let expected = SystemTime::UNIX_EPOCH + std::time::Duration::new(1_000_000_000, 10);
71        assert_eq!(actual, expected);
72    }
73
74    #[test]
75    fn std_to_instant() {
76        let sys_time = SystemTime::UNIX_EPOCH + std::time::Duration::new(1_000_000_000, 10);
77        let actual: Instant = sys_time.into();
78        let expected = Instant::new(1_000_000_000, 10);
79        assert_eq!(actual, expected);
80    }
81}