1use chrono::{DateTime, Utc};
8
9pub trait Clock: Send + Sync {
11 fn now(&self) -> DateTime<Utc>;
13}
14
15#[derive(Debug, Default)]
17pub struct SystemClock;
18
19impl Clock for SystemClock {
20 fn now(&self) -> DateTime<Utc> {
21 Utc::now()
22 }
23}
24
25#[derive(Debug, Clone)]
27pub struct FixedClock(pub DateTime<Utc>);
28
29impl FixedClock {
30 #[must_use]
34 #[allow(clippy::expect_used, clippy::missing_panics_doc)]
35 pub fn from_rfc3339(s: &str) -> Self {
36 let dt = DateTime::parse_from_rfc3339(s)
37 .expect("FixedClock::from_rfc3339: invalid RFC3339 timestamp")
38 .with_timezone(&Utc);
39 Self(dt)
40 }
41}
42
43impl Clock for FixedClock {
44 fn now(&self) -> DateTime<Utc> {
45 self.0
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn fixed_clock_returns_same_instant_repeatedly() {
55 let clock = FixedClock::from_rfc3339("2026-01-01T00:00:00Z");
56 let a = clock.now();
57 let b = clock.now();
58 assert_eq!(a, b);
59 }
60
61 #[test]
62 fn fixed_clock_from_rfc3339_parses_utc() {
63 let clock = FixedClock::from_rfc3339("2026-01-01T00:00:00Z");
64 assert_eq!(clock.0.to_rfc3339(), "2026-01-01T00:00:00+00:00");
65 }
66
67 #[test]
68 fn system_clock_returns_recent_time() {
69 let clock = SystemClock;
70 let now = clock.now();
71 let real_now = Utc::now();
72 let delta = (real_now - now).num_seconds().abs();
73 assert!(delta < 2, "SystemClock should be close to Utc::now()");
74 }
75}