1use std::time::{SystemTime, UNIX_EPOCH};
9
10pub fn now_ms() -> u64 {
13 SystemTime::now()
14 .duration_since(UNIX_EPOCH)
15 .map(|d| u64::try_from(d.as_millis()).unwrap_or(u64::MAX))
16 .unwrap_or(0)
17}
18
19pub fn iso8601_ms(epoch_ms: u64) -> String {
23 let secs = epoch_ms / crate::units::MS_PER_SEC;
24 let ms = epoch_ms % crate::units::MS_PER_SEC;
25 let days = secs / crate::units::SECS_PER_DAY;
26 let rem = secs % crate::units::SECS_PER_DAY;
27 let (h, m, s) = (rem / 3600, (rem % 3600) / 60, rem % 60);
28 let (year, month, day) = civil_from_days(days as i64);
29 format!("{year:04}-{month:02}-{day:02}T{h:02}:{m:02}:{s:02}.{ms:03}Z")
30}
31
32pub fn now_iso8601() -> String {
34 iso8601_ms(now_ms())
35}
36
37pub fn elapsed_us(started: std::time::Instant) -> u64 {
40 u64::try_from(started.elapsed().as_micros()).unwrap_or(u64::MAX)
41}
42
43fn civil_from_days(z: i64) -> (i64, u32, u32) {
45 let z = z + 719_468;
46 let era = if z >= 0 { z } else { z - 146_096 } / 146_097;
47 let doe = z - era * 146_097;
48 let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365;
49 let y = yoe + era * 400;
50 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
51 let mp = (5 * doy + 2) / 153;
52 let d = doy - (153 * mp + 2) / 5 + 1;
53 let m = if mp < 10 { mp + 3 } else { mp - 9 };
54 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
55 (if m <= 2 { y + 1 } else { y }, m as u32, d as u32)
56}
57
58#[cfg(test)]
59mod tests {
60 #![allow(clippy::indexing_slicing)]
61
62 use super::*;
63
64 #[test]
65 fn epoch_zero() {
66 assert_eq!(iso8601_ms(0), "1970-01-01T00:00:00.000Z");
67 }
68
69 #[test]
70 fn known_timestamp() {
71 assert_eq!(iso8601_ms(1_786_320_000_000), "2026-08-10T00:00:00.000Z");
73 }
74
75 #[test]
76 fn leap_year_feb_29() {
77 assert_eq!(iso8601_ms(1_709_210_096_789), "2024-02-29T12:34:56.789Z");
79 }
80
81 #[test]
82 fn year_2038_safe() {
83 assert_eq!(iso8601_ms(4_102_444_800_000), "2100-01-01T00:00:00.000Z");
85 }
86
87 #[test]
88 fn now_is_sane() {
89 let now = now_ms();
90 assert!(now > 1_700_000_000_000, "clock reads before Nov 2023: {now}");
91 let iso = now_iso8601();
92 assert!(iso.ends_with('Z') && iso.len() == 24, "bad iso format: {iso}");
93 }
94
95 #[test]
96 fn civil_from_days_exercises_month_and_day_arithmetic() {
97 let cases: &[(u64, &str)] = &[
102 (0, "1970-01-01T00:00:00.000Z"),
103 (1_709_251_200_000, "2024-03-01T00:00:00.000Z"),
104 (4_102_358_400_000, "2099-12-31T00:00:00.000Z"),
105 (951_782_400_000, "2000-02-29T00:00:00.000Z"),
106 ];
107 for (epoch_ms, expected) in cases {
108 assert_eq!(&iso8601_ms(*epoch_ms), expected, "epoch_ms={epoch_ms}");
109 }
110 }
111
112 #[test]
119 fn iso8601_ms_always_emits_utc_zulu() {
120 for &epoch_ms in &[0u64, 1_000, 1_786_320_000_000, 4_102_444_800_000] {
121 let iso = iso8601_ms(epoch_ms);
122 assert!(iso.ends_with('Z'), "must end with Z: {iso}");
123 assert!(!iso.contains('+'), "must not carry a `+HH:MM` offset: {iso}");
124 assert!(
125 !iso[1..].contains('-') || iso.matches('-').count() == 2,
126 "only date separators are allowed: {iso}",
127 );
128 }
129 }
130
131 #[test]
133 fn iso8601_ms_millisecond_precision_is_lossless() {
134 let base = 1_786_320_000_000u64; for ms in 0..1000 {
136 let iso = iso8601_ms(base + ms);
137 let expected = format!("2026-08-10T00:00:00.{ms:03}Z");
138 assert_eq!(iso, expected, "ms={ms}");
139 }
140 }
141
142 #[test]
145 fn iso8601_ms_is_deterministic_across_calls() {
146 let cases = [0u64, 1_000, 86_400_000, 1_786_320_000_000, 4_102_444_800_000];
147 for &epoch_ms in &cases {
148 let a = iso8601_ms(epoch_ms);
149 let b = iso8601_ms(epoch_ms);
150 let c = iso8601_ms(epoch_ms);
151 assert_eq!(a, b);
152 assert_eq!(b, c);
153 }
154 }
155
156 #[test]
160 fn iso8601_ms_stays_24_chars_through_year_9999() {
161 let last_4digit_ms = 253_402_300_799_999u64;
163 let iso = iso8601_ms(last_4digit_ms);
164 assert_eq!(iso, "9999-12-31T23:59:59.999Z");
165 assert_eq!(iso.len(), 24, "must stay at 24 chars through year 9999");
166 }
167
168 #[test]
173 fn iso8601_ms_does_not_panic_at_u64_max() {
174 let iso = iso8601_ms(u64::MAX);
175 assert!(iso.ends_with('Z'), "still emits UTC-Z: {iso}");
176 assert!(iso.len() >= 24, "still valid-shape: {iso}");
177 }
178
179 #[test]
185 fn now_ms_never_panics_and_is_monotonic_under_normal_operation() {
186 let mut previous = now_ms();
187 for _ in 0..1_000 {
188 let current = now_ms();
189 assert!(
190 current >= previous,
191 "wall clock ran backward: {previous} -> {current}",
192 );
193 previous = current;
194 }
195 }
196
197 #[test]
200 fn now_iso8601_shape_holds_for_real_clock() {
201 for _ in 0..100 {
202 let iso = now_iso8601();
203 assert!(iso.ends_with('Z'), "{iso}");
204 assert_eq!(iso.len(), 24, "{iso}");
205 let bytes = iso.as_bytes();
207 assert_eq!(bytes[4], b'-');
208 assert_eq!(bytes[7], b'-');
209 assert_eq!(bytes[10], b'T');
210 assert_eq!(bytes[13], b':');
211 assert_eq!(bytes[16], b':');
212 assert_eq!(bytes[19], b'.');
213 }
214 }
215
216 #[test]
219 fn iso8601_ms_leap_year_boundaries_are_correct() {
220 let cases: &[(u64, &str)] = &[
227 (951_696_000_000, "2000-02-29T00:00:00.000Z"), (4_107_456_000_000, "2100-03-01T00:00:00.000Z"), (
230 13_569_465_600_000 + 58 * crate::units::MS_PER_DAY,
231 "2400-02-29T00:00:00.000Z",
232 ), (1_709_078_400_000, "2024-02-29T00:00:00.000Z"), (1_677_542_400_000, "2023-03-01T00:00:00.000Z"), ];
236 for &(feb_28_ms, expected_next) in cases {
237 let next_day = iso8601_ms(feb_28_ms + crate::units::MS_PER_DAY);
238 assert_eq!(next_day, expected_next, "feb_28_ms={feb_28_ms}");
239 }
240 }
241
242 #[test]
246 fn elapsed_us_never_panics_and_is_monotone() {
247 let started = std::time::Instant::now();
248 let a = elapsed_us(started);
249 let b = elapsed_us(started);
250 assert!(b >= a, "elapsed_us reversed: {a} -> {b}");
251 assert!(a < u64::MAX);
252 }
253}
254
255#[cfg(test)]
256mod calendar_tests {
257 #[test]
262 fn iso8601_ms_pins_known_dates() {
263 assert_eq!(super::iso8601_ms(0), "1970-01-01T00:00:00.000Z");
264 assert_eq!(super::iso8601_ms(951_782_400_000), "2000-02-29T00:00:00.000Z");
265 assert_eq!(super::iso8601_ms(4_107_542_399_000), "2100-02-28T23:59:59.000Z");
266 }
267}