system_clock.rs

 1use chrono::{DateTime, Utc};
 2
 3pub trait SystemClock: Send + Sync {
 4    /// Returns the current date and time in UTC.
 5    fn utc_now(&self) -> DateTime<Utc>;
 6}
 7
 8pub struct RealSystemClock;
 9
10impl SystemClock for RealSystemClock {
11    fn utc_now(&self) -> DateTime<Utc> {
12        Utc::now()
13    }
14}
15
16#[cfg(any(test, feature = "test-support"))]
17pub struct FakeSystemClockState {
18    now: DateTime<Utc>,
19}
20
21#[cfg(any(test, feature = "test-support"))]
22pub struct FakeSystemClock {
23    // Use an unfair lock to ensure tests are deterministic.
24    state: parking_lot::Mutex<FakeSystemClockState>,
25}
26
27#[cfg(any(test, feature = "test-support"))]
28impl Default for FakeSystemClock {
29    fn default() -> Self {
30        Self::new(Utc::now())
31    }
32}
33
34#[cfg(any(test, feature = "test-support"))]
35impl FakeSystemClock {
36    pub fn new(now: DateTime<Utc>) -> Self {
37        let state = FakeSystemClockState { now };
38
39        Self {
40            state: parking_lot::Mutex::new(state),
41        }
42    }
43
44    pub fn set_now(&self, now: DateTime<Utc>) {
45        self.state.lock().now = now;
46    }
47
48    /// Advances the [`FakeSystemClock`] by the specified [`Duration`](chrono::Duration).
49    pub fn advance(&self, duration: chrono::Duration) {
50        self.state.lock().now += duration;
51    }
52}
53
54#[cfg(any(test, feature = "test-support"))]
55impl SystemClock for FakeSystemClock {
56    fn utc_now(&self) -> DateTime<Utc> {
57        self.state.lock().now
58    }
59}