use chrono::{Local, NaiveDate};
pub struct Clock {
demo: bool,
}
impl Clock {
pub fn new(demo: bool) -> Self {
Self { demo }
}
pub fn now_formatted(&self, format_str: &str) -> String {
let fmt = format_str.replace("\\n", "\n");
if self.demo {
let demo_dt = NaiveDate::from_ymd_opt(2007, 1, 9)
.unwrap()
.and_hms_opt(9, 41, 0)
.unwrap();
demo_dt.format(&fmt).to_string()
} else {
Local::now().format(&fmt).to_string()
}
}
pub fn millis_until_next_tick(&self, format_str: &str) -> u64 {
if self.demo {
return 3600_000; }
if format_str.contains("%f")
|| format_str.contains("%3f")
|| format_str.contains("%6f")
|| format_str.contains("%9f")
|| format_str.contains("%N")
{
return 33;
}
let now = Local::now();
let millis = now.timestamp_subsec_millis();
let delay = 1000 - (millis % 1000) + 2; u64::from(delay)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_demo_clock_formatting() {
let clock = Clock::new(true);
let formatted = clock.now_formatted("%Y-%m-%d %H:%M:%S");
assert_eq!(formatted, "2007-01-09 09:41:00");
}
#[test]
fn test_millis_until_next_tick_bounds() {
let clock = Clock::new(false);
let delay = clock.millis_until_next_tick("%H:%M:%S");
assert!(delay >= 2 && delay <= 1002, "Delay {} out of expected range", delay);
}
#[test]
fn test_subsecond_format_detection() {
let clock = Clock::new(false);
let delay = clock.millis_until_next_tick("%H:%M:%S.%3f");
assert_eq!(delay, 33);
}
}