Skip to main content

zenobuf_core/
time.rs

1//! Time utilities for Zenobuf
2
3use std::time::{Duration, SystemTime, UNIX_EPOCH};
4
5/// Time representation for Zenobuf
6///
7/// This struct represents a point in time, similar to the Time message in ROS.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
9pub struct Time {
10    /// Seconds since the Unix epoch
11    pub sec: u64,
12    /// Nanoseconds since the last second
13    pub nsec: u32,
14}
15
16impl Time {
17    /// Creates a new Time from seconds and nanoseconds
18    pub fn new(sec: u64, nsec: u32) -> Self {
19        let mut time = Self { sec, nsec };
20        time.normalize();
21        time
22    }
23
24    /// Creates a Time representing the current time
25    pub fn now() -> Self {
26        let now = SystemTime::now()
27            .duration_since(UNIX_EPOCH)
28            .expect("System time before Unix epoch");
29        Self::from(now)
30    }
31
32    /// Creates a Time from a Duration since the Unix epoch
33    pub fn from_duration(duration: Duration) -> Self {
34        Self::new(duration.as_secs(), duration.subsec_nanos())
35    }
36
37    /// Converts the Time to a Duration since the Unix epoch
38    pub fn to_duration(&self) -> Duration {
39        Duration::new(self.sec, self.nsec)
40    }
41
42    /// Normalizes the Time by carrying over nanoseconds to seconds
43    fn normalize(&mut self) {
44        if self.nsec >= 1_000_000_000 {
45            self.sec += u64::from(self.nsec) / 1_000_000_000;
46            self.nsec %= 1_000_000_000;
47        }
48    }
49
50    /// Adds a Duration to the Time
51    pub fn add(&self, duration: Duration) -> Self {
52        let duration_since_epoch = self.to_duration();
53        let new_duration = duration_since_epoch + duration;
54        Self::from_duration(new_duration)
55    }
56
57    /// Subtracts a Duration from the Time
58    pub fn sub(&self, duration: Duration) -> Self {
59        let duration_since_epoch = self.to_duration();
60        let new_duration = duration_since_epoch
61            .checked_sub(duration)
62            .unwrap_or_else(|| Duration::new(0, 0));
63        Self::from_duration(new_duration)
64    }
65}
66
67impl From<Duration> for Time {
68    fn from(duration: Duration) -> Self {
69        Self::from_duration(duration)
70    }
71}
72
73impl From<SystemTime> for Time {
74    fn from(time: SystemTime) -> Self {
75        let duration = time
76            .duration_since(UNIX_EPOCH)
77            .expect("System time before Unix epoch");
78        Self::from(duration)
79    }
80}
81
82/// Duration representation for Zenobuf
83///
84/// This struct represents a duration, similar to the Duration message in ROS.
85#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
86pub struct ZenobufDuration {
87    /// Seconds
88    pub sec: i32,
89    /// Nanoseconds
90    pub nsec: i32,
91}
92
93impl ZenobufDuration {
94    /// Creates a new Duration from seconds and nanoseconds
95    pub fn new(sec: i32, nsec: i32) -> Self {
96        let mut duration = Self { sec, nsec };
97        duration.normalize();
98        duration
99    }
100
101    /// Creates a Duration from a std::time::Duration
102    pub fn from_std(duration: Duration) -> Self {
103        Self::new(duration.as_secs() as i32, duration.subsec_nanos() as i32)
104    }
105
106    /// Converts the Duration to a std::time::Duration
107    pub fn to_std(&self) -> Duration {
108        Duration::new(self.sec as u64, self.nsec as u32)
109    }
110
111    /// Normalizes the Duration by carrying over nanoseconds to seconds
112    fn normalize(&mut self) {
113        if self.nsec >= 1_000_000_000 {
114            self.sec += self.nsec / 1_000_000_000;
115            self.nsec %= 1_000_000_000;
116        } else if self.nsec < 0 {
117            let sec_adj = (-self.nsec / 1_000_000_000) + 1;
118            self.sec -= sec_adj;
119            self.nsec += sec_adj * 1_000_000_000;
120        }
121    }
122}
123
124impl From<Duration> for ZenobufDuration {
125    fn from(duration: Duration) -> Self {
126        Self::from_std(duration)
127    }
128}
129
130impl From<ZenobufDuration> for Duration {
131    fn from(duration: ZenobufDuration) -> Self {
132        duration.to_std()
133    }
134}