Skip to main content

zeph_common/
clock.rs

1// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Injectable wall-clock source (#6361).
5//!
6//! [`ClockSource`] abstracts "what time is it now" so callers on the agent's time-awareness
7//! paths (the `get_current_time` tool and periodic time-reminder injection) never call
8//! [`std::time::SystemTime::now`] directly — tests substitute [`FixedClock`] instead, keeping
9//! them deterministic. Deliberately returns [`std::time::SystemTime`], not a `chrono` type: this
10//! crate has no external date/time dependency (see [`crate::timestamp`]).
11
12use std::time::SystemTime;
13
14/// A source of the current wall-clock time.
15///
16/// Implementors must guarantee `now()` is cheap (no I/O, no blocking) since it is called on
17/// hot paths (tool execution, per-turn system-prompt assembly). Callers may assume the
18/// returned [`SystemTime`] reflects UTC "now" for [`SystemClock`], or a fixed, caller-chosen
19/// instant for [`FixedClock`].
20pub trait ClockSource: Send + Sync {
21    /// Returns the current time.
22    fn now(&self) -> SystemTime;
23}
24
25/// Production clock: wraps [`SystemTime::now`].
26#[derive(Debug, Clone, Default)]
27pub struct SystemClock;
28
29impl ClockSource for SystemClock {
30    fn now(&self) -> SystemTime {
31        SystemTime::now()
32    }
33}
34
35/// Test/repro clock: always returns the same fixed instant.
36///
37/// Not gated behind `#[cfg(test)]` — reproducible-run harnesses outside this crate may also
38/// want a deterministic clock (mirrors Codex's `clock_source` override).
39#[derive(Debug, Clone)]
40pub struct FixedClock(pub SystemTime);
41
42impl ClockSource for FixedClock {
43    fn now(&self) -> SystemTime {
44        self.0
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn system_clock_returns_recent_time() {
54        let before = SystemTime::now();
55        let observed = SystemClock.now();
56        let after = SystemTime::now();
57        assert!(observed >= before && observed <= after);
58    }
59
60    #[test]
61    fn fixed_clock_returns_the_same_instant_every_call() {
62        let t = SystemTime::UNIX_EPOCH + std::time::Duration::from_secs(1_700_000_000);
63        let clock = FixedClock(t);
64        assert_eq!(clock.now(), t);
65        assert_eq!(clock.now(), t);
66    }
67}