use std::time::{Duration, SystemTime, UNIX_EPOCH};
pub const fn days(n: u64) -> Duration {
Duration::from_secs(n * 86_400)
}
pub struct Clock;
impl Clock {
pub fn now_secs() -> i64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as i64
}
pub fn now_millis() -> i64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64
}
pub fn millis_ago(d: Duration) -> i64 {
Self::now_millis() - d.as_millis() as i64
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn now_secs_is_positive_and_monotonicish() {
let a = Clock::now_secs();
let b = Clock::now_secs();
assert!(a > 1_700_000_000, "clock should be well past 2023: {a}");
assert!(b >= a, "time should not go backwards within a test");
}
#[test]
fn days_converts_to_seconds() {
assert_eq!(days(0), Duration::ZERO);
assert_eq!(days(1).as_secs(), 86_400);
assert_eq!(days(30).as_secs(), 2_592_000);
}
#[test]
fn millis_ago_subtracts_the_window() {
let before = Clock::now_millis();
let cutoff = Clock::millis_ago(days(1));
let after = Clock::now_millis();
assert!(cutoff <= before - 86_400_000 + 5);
assert!(cutoff >= after - 86_400_000 - 5);
}
#[test]
fn now_millis_is_positive_and_consistent_with_secs() {
let millis = Clock::now_millis();
let secs = Clock::now_secs();
assert!(
millis > 1_700_000_000_000,
"millis clock should be well past 2023: {millis}"
);
assert!(
(millis / 1000 - secs).abs() <= 1,
"now_millis/1000 ({}) must track now_secs ({secs})",
millis / 1000
);
}
}