1use time::OffsetDateTime;
4
5pub trait Clock: Send + Sync {
7 fn now(&self) -> OffsetDateTime;
9}
10
11pub(crate) fn nanos(at: OffsetDateTime) -> i64 {
13 i64::try_from(at.unix_timestamp_nanos()).expect("a time before 2262")
14}
15
16pub(crate) fn from_nanos(at: i64) -> Option<OffsetDateTime> {
19 OffsetDateTime::from_unix_timestamp_nanos(i128::from(at)).ok()
20}
21
22pub 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 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}