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
22#[derive(Debug, Clone, Copy, Default)]
24pub struct SystemClock;
25
26impl Clock for SystemClock {
27 fn now(&self) -> OffsetDateTime {
28 OffsetDateTime::now_utc()
29 }
30}
31
32#[cfg(test)]
33pub(crate) use manual::ManualClock;
34
35#[cfg(test)]
36mod manual {
37 use std::sync::Mutex;
38
39 use time::OffsetDateTime;
40
41 use super::Clock;
42
43 pub(crate) struct ManualClock(Mutex<OffsetDateTime>);
45
46 impl ManualClock {
47 pub(crate) fn at(now: OffsetDateTime) -> ManualClock {
48 ManualClock(Mutex::new(now))
49 }
50
51 pub(crate) fn set(&self, now: OffsetDateTime) {
52 *self.0.lock().expect("clock") = now;
53 }
54 }
55
56 impl Clock for ManualClock {
57 fn now(&self) -> OffsetDateTime {
58 *self.0.lock().expect("clock")
59 }
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn the_system_clock_is_close_to_now() {
69 let before = OffsetDateTime::now_utc();
70 let now = SystemClock.now();
71 let after = OffsetDateTime::now_utc();
72 assert!(
73 before <= now && now <= after,
74 "the system clock reads the time now: {before} <= {now} <= {after}"
75 );
76 assert!(
77 now.offset().is_utc(),
78 "the trait promises UTC, and comparing instants alone cannot tell"
79 );
80 }
81}