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
41            .duration_since(SystemTime::UNIX_EPOCH)
42            .expect("time must be after Unix epoch");
43        let seconds = duration.as_secs();
44        let nanos = duration.subsec_nanos();
45        Self { seconds, nanos }
46    }
47}
48
49impl From<Instant> for SystemTime {
50    fn from(time: Instant) -> Self {
51        Self::UNIX_EPOCH + std::time::Duration::new(time.seconds, time.nanos)
52    }
53}
54
55#[cfg(test)]
56mod test {
57    use super::*;
58
59    #[test]
60    fn new_instant() {
61        let instant = Instant::new(1_000_000_000, 10);
62        assert_eq!(instant.seconds, 1_000_000_000);
63        assert_eq!(instant.nanos, 10);
64    }
65
66    #[test]
67    #[should_panic = "nanos must be less than 1000000000"]
68    fn new_instant_invalid_nanos() {
69        let _ = Instant::new(1_000_000_000, 1_000_000_000);
70    }
71
72    #[test]
73    fn instant_to_std() {
74        let actual: SystemTime = Instant::new(1_000_000_000, 10).into();
75        let expected = SystemTime::UNIX_EPOCH + std::time::Duration::new(1_000_000_000, 10);
76        assert_eq!(actual, expected);
77    }
78
79    #[test]
80    fn std_to_instant() {
81        let sys_time = SystemTime::UNIX_EPOCH + std::time::Duration::new(1_000_000_000, 10);
82        let actual: Instant = sys_time.into();
83        let expected = Instant::new(1_000_000_000, 10);
84        assert_eq!(actual, expected);
85    }
86}