Skip to main content

vcon_server/
clock.rs

1//! Time, behind an interface so tests can set it.
2
3use time::OffsetDateTime;
4
5/// Where the server gets the time.
6pub trait Clock: Send + Sync {
7    /// The time now, in UTC.
8    fn now(&self) -> OffsetDateTime;
9}
10
11/// A time as the catalogs keep it: nanoseconds since the Unix epoch.
12pub(crate) fn nanos(at: OffsetDateTime) -> i64 {
13    i64::try_from(at.unix_timestamp_nanos()).expect("a time before 2262")
14}
15
16/// A time the catalogs kept as `nanos` wrote it, or None if it is out of
17/// range.
18pub(crate) fn from_nanos(at: i64) -> Option<OffsetDateTime> {
19    OffsetDateTime::from_unix_timestamp_nanos(i128::from(at)).ok()
20}
21
22/// The system's clock.
23pub struct SystemClock;
24
25impl Clock for SystemClock {
26    fn now(&self) -> OffsetDateTime {
27        OffsetDateTime::now_utc()
28    }
29}
30
31#[cfg(test)]
32pub(crate) use manual::ManualClock;
33
34#[cfg(test)]
35mod manual {
36    use std::sync::Mutex;
37
38    use time::OffsetDateTime;
39
40    use super::Clock;
41
42    /// A clock that stands still until a test moves it.
43    pub(crate) struct ManualClock(Mutex<OffsetDateTime>);
44
45    impl ManualClock {
46        pub(crate) fn at(now: OffsetDateTime) -> ManualClock {
47            ManualClock(Mutex::new(now))
48        }
49
50        pub(crate) fn set(&self, now: OffsetDateTime) {
51            *self.0.lock().expect("clock") = now;
52        }
53    }
54
55    impl Clock for ManualClock {
56        fn now(&self) -> OffsetDateTime {
57            *self.0.lock().expect("clock")
58        }
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use time::macros::datetime;
65
66    use super::*;
67
68    #[test]
69    fn the_system_clock_is_close_to_now() {
70        let before = OffsetDateTime::now_utc();
71        let now = SystemClock.now();
72        let after = OffsetDateTime::now_utc();
73        assert!(before <= now && now <= after);
74    }
75
76    #[test]
77    fn a_manual_clock_moves_only_when_set() {
78        let clock = ManualClock::at(datetime!(2026-10-23 12:00 UTC));
79        assert_eq!(clock.now(), datetime!(2026-10-23 12:00 UTC));
80        clock.set(datetime!(2026-10-24 12:00 UTC));
81        assert_eq!(clock.now(), datetime!(2026-10-24 12:00 UTC));
82    }
83}