1use chrono::{DateTime, Utc};
10
11pub fn format(reset: Option<DateTime<Utc>>, now: DateTime<Utc>) -> String {
16 let Some(reset) = reset else {
17 return "—".to_string();
18 };
19
20 let diff = reset.signed_duration_since(now);
21 let secs = diff.num_seconds();
22 if secs <= 0 {
23 return "now".to_string();
24 }
25
26 let days = secs / 86_400;
27 let hours = (secs % 86_400) / 3_600;
28 let mins = (secs % 3_600) / 60;
29
30 if days > 0 {
31 format!("{days}d {hours}h")
32 } else {
33 format!("{hours}h {mins:02}m")
34 }
35}
36
37#[cfg(test)]
38mod tests {
39 use super::*;
40 use chrono::TimeZone;
41
42 fn at(year: i32, month: u32, day: u32, h: u32, m: u32) -> DateTime<Utc> {
43 Utc.with_ymd_and_hms(year, month, day, h, m, 0).unwrap()
44 }
45
46 #[test]
47 fn missing_reset_renders_em_dash() {
48 let now = at(2026, 5, 23, 12, 0);
49 assert_eq!(format(None, now), "—");
50 }
51
52 #[test]
53 fn past_reset_renders_now() {
54 let now = at(2026, 5, 23, 12, 0);
55 let reset = at(2026, 5, 23, 11, 0);
56 assert_eq!(format(Some(reset), now), "now");
57 }
58
59 #[test]
60 fn exact_zero_renders_now() {
61 let t = at(2026, 5, 23, 12, 0);
63 assert_eq!(format(Some(t), t), "now");
64 }
65
66 #[test]
67 fn hours_minutes_zero_padded() {
68 let now = at(2026, 5, 23, 12, 0);
69 let reset = at(2026, 5, 23, 13, 5); assert_eq!(format(Some(reset), now), "1h 05m");
71 }
72
73 #[test]
74 fn hours_minutes_no_days_under_one_day() {
75 let now = at(2026, 5, 23, 12, 0);
76 let reset = at(2026, 5, 24, 11, 59); assert_eq!(format(Some(reset), now), "23h 59m");
78 }
79
80 #[test]
81 fn one_day_one_hour() {
82 let now = at(2026, 5, 23, 12, 0);
83 let reset = at(2026, 5, 24, 13, 30); assert_eq!(format(Some(reset), now), "1d 1h");
85 }
86
87 #[test]
88 fn multiple_days_drops_minutes() {
89 let now = at(2026, 5, 23, 12, 0);
90 let reset = at(2026, 5, 27, 13, 45); assert_eq!(format(Some(reset), now), "4d 1h");
92 }
93
94 #[test]
95 fn one_second_remaining_renders_zero_hours() {
96 let now = at(2026, 5, 23, 12, 0);
98 let reset = now + chrono::Duration::seconds(1);
99 assert_eq!(format(Some(reset), now), "0h 00m");
100 }
101}