1use crate::{Clock, Timer};
2use futures::future::BoxFuture;
3use jiff::tz::TimeZone;
4use jiff::Timestamp;
5use std::time::Duration;
6
7#[derive(Debug)]
9pub struct WallClock;
10
11impl Clock for WallClock {
12 fn now(&self) -> Timestamp {
13 Timestamp::now()
14 }
15}
16
17pub fn system_tz() -> TimeZone {
26 TimeZone::system()
27}
28
29#[derive(Debug)]
31pub struct TokioTimer;
32
33impl Timer for TokioTimer {
34 fn sleep(&self, dur: Duration) -> BoxFuture<'static, ()> {
35 Box::pin(async move {
36 tokio::time::sleep(dur).await;
37 })
38 }
39
40 fn next_tick(&self) -> BoxFuture<'static, ()> {
41 Box::pin(async {
42 tokio::task::yield_now().await;
43 })
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50 use crate::Clock as ClockTrait;
51 use crate::Timer as TimerTrait;
52 use std::sync::Arc;
53 use std::time::Instant;
54
55 fn assert_send_sync<T: Send + Sync>() {}
56
57 #[test]
58 fn wall_clock_and_tokio_timer_are_send_sync() {
59 assert_send_sync::<WallClock>();
60 assert_send_sync::<TokioTimer>();
61 }
62
63 #[test]
64 fn now_is_recent() {
65 let before = Timestamp::now();
66 let clock = WallClock;
67 let t = clock.now();
68 let after = Timestamp::now();
69 assert!(t >= before - jiff::SignedDuration::from_secs(1));
70 assert!(t <= after + jiff::SignedDuration::from_secs(1));
71 }
72
73 #[test]
74 fn now_unix_millis_positive_and_recent() {
75 let before_ms = Timestamp::now().as_millisecond();
76 let clock = WallClock;
77 let ms = clock.now_unix_millis();
78 let after_ms = Timestamp::now().as_millisecond();
79 assert!(ms > 0, "unix millis must be positive");
80 assert!(ms >= before_ms - 100, "must be >= before sample");
81 assert!(ms <= after_ms + 100, "must be <= after sample");
82 }
83
84 #[tokio::test]
85 async fn tokio_timer_sleep_completes() {
86 let timer = TokioTimer;
87 let start = Instant::now();
88 timer.sleep(Duration::from_millis(50)).await;
89 let elapsed = start.elapsed();
90 assert!(elapsed.as_millis() >= 45, "sleep must take at least 45ms");
91 assert!(elapsed.as_millis() < 500, "sleep must not take more than 500ms");
92 }
93
94 #[tokio::test]
95 async fn tokio_timer_next_tick_completes_immediately() {
96 let timer = TokioTimer;
97 let start = Instant::now();
98 timer.next_tick().await;
99 assert!(start.elapsed().as_millis() < 100);
100 }
101
102 #[test]
103 fn wall_clock_arc_dyn_dispatch() {
104 let c: Arc<dyn ClockTrait> = Arc::new(WallClock);
105 let _ = c.now();
106 }
107
108 #[test]
109 fn tokio_timer_arc_dyn_dispatch() {
110 let t: Arc<dyn TimerTrait> = Arc::new(TokioTimer);
111 let _ = t.sleep(Duration::ZERO);
112 }
113}