commonware_utils/
time.rs

1//! Utility functions for `std::time`.
2
3use std::time::{Duration, SystemTime};
4
5/// Extension trait to add methods to `std::time::SystemTime`
6pub trait SystemTimeExt {
7    /// Returns the duration since the Unix epoch.
8    ///
9    /// Panics if the system time is before the Unix epoch.
10    fn epoch(&self) -> Duration;
11
12    /// Returns the number of milliseconds (rounded down) since the Unix epoch.
13    ///
14    /// Panics if the system time is before the Unix epoch.
15    /// Saturates at `u64::MAX`.
16    fn epoch_millis(&self) -> u64;
17}
18
19impl SystemTimeExt for SystemTime {
20    fn epoch(&self) -> Duration {
21        self.duration_since(std::time::UNIX_EPOCH)
22            .expect("failed to get epoch time")
23    }
24
25    fn epoch_millis(&self) -> u64 {
26        self.epoch().as_millis().min(u64::MAX as u128) as u64
27    }
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33
34    #[test]
35    fn test_epoch() {
36        let time = SystemTime::UNIX_EPOCH;
37        assert_eq!(time.epoch(), Duration::from_secs(0));
38
39        let time = SystemTime::UNIX_EPOCH + Duration::from_secs(1) + Duration::from_millis(1);
40        assert_eq!(time.epoch(), Duration::from_millis(1_001));
41    }
42
43    #[test]
44    #[should_panic(expected = "failed to get epoch time")]
45    fn test_epoch_panics() {
46        let time = SystemTime::UNIX_EPOCH - Duration::from_secs(1);
47        time.epoch();
48    }
49
50    #[test]
51    fn test_epoch_millis() {
52        let time = SystemTime::UNIX_EPOCH;
53        assert_eq!(time.epoch_millis(), 0);
54
55        let time = SystemTime::UNIX_EPOCH + Duration::from_secs(1) + Duration::from_millis(1);
56        assert_eq!(time.epoch_millis(), 1_001);
57
58        // Rounds nanoseconds down
59        let time = SystemTime::UNIX_EPOCH + Duration::from_secs(1) + Duration::from_nanos(999_999);
60        assert_eq!(time.epoch_millis(), 1_000);
61
62        // Saturates at u64::MAX
63        let time = SystemTime::UNIX_EPOCH + Duration::from_millis(u64::MAX);
64        assert_eq!(time.epoch_millis(), u64::MAX);
65        let time = time + Duration::from_millis(1);
66        assert_eq!(time.epoch_millis(), u64::MAX);
67    }
68
69    #[test]
70    #[should_panic(expected = "failed to get epoch time")]
71    fn test_epoch_millis_panics() {
72        let time = SystemTime::UNIX_EPOCH - Duration::from_secs(1);
73        time.epoch_millis();
74    }
75}