Skip to main content

polyoxide_venue/
time.rs

1//! Wall-clock time as venues send it.
2
3// `web_time` re-exports `std`'s types on every target but wasm32, where it
4// reads the browser's clock.
5#[cfg(not(target_arch = "wasm32"))]
6use std::time::{SystemTime, UNIX_EPOCH};
7#[cfg(target_arch = "wasm32")]
8use web_time::{SystemTime, UNIX_EPOCH};
9
10/// Milliseconds since the Unix epoch, the unit venues stamp orders and
11/// frames with.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
13pub struct UnixMillis(pub u64);
14
15impl UnixMillis {
16    /// Now, by the system clock. A clock that reads before 1970 gives
17    /// `UnixMillis(0)`.
18    pub fn now() -> Self {
19        Self::at(SystemTime::now()) // runtime-gate: the wall clock is never injected
20    }
21
22    fn at(time: SystemTime) -> Self {
23        Self(time.duration_since(UNIX_EPOCH).map_or(0, |since| {
24            u64::try_from(since.as_millis()).unwrap_or(u64::MAX)
25        }))
26    }
27}
28
29#[cfg(test)]
30mod tests {
31    use std::time::Duration;
32
33    use super::*;
34
35    #[test]
36    fn now_is_after_2026_and_never_runs_backwards_between_two_calls() {
37        // 2026-01-01T00:00:00Z.
38        let first = UnixMillis::now();
39        assert!(first > UnixMillis(1_767_225_600_000), "{first:?}");
40        let second = UnixMillis::now();
41        assert!(second >= first, "{second:?} < {first:?}");
42    }
43
44    #[test]
45    fn a_clock_before_1970_reads_zero() {
46        assert_eq!(
47            UnixMillis::at(UNIX_EPOCH - Duration::from_secs(1)),
48            UnixMillis(0)
49        );
50        assert_eq!(
51            UnixMillis::at(UNIX_EPOCH + Duration::from_millis(1_500)),
52            UnixMillis(1_500)
53        );
54    }
55}