Skip to main content

tokenburn_core/utils/
time.rs

1//! Timestamp helpers.
2
3use chrono::{DateTime, NaiveDateTime, Utc};
4
5/// Parse the timestamp flavours found in the agents' logs.
6///
7/// Accepts RFC 3339 (`2026-05-01T10:00:00Z`, with offset or fractional
8/// seconds) and naive `YYYY-MM-DD[T ]HH:MM:SS[.f]` (interpreted as UTC).
9pub fn parse_ts(s: &str) -> Option<DateTime<Utc>> {
10    let s = s.trim();
11    if let Ok(dt) = DateTime::parse_from_rfc3339(s) {
12        return Some(dt.with_timezone(&Utc));
13    }
14    for fmt in ["%Y-%m-%dT%H:%M:%S%.f", "%Y-%m-%d %H:%M:%S%.f"] {
15        if let Ok(n) = NaiveDateTime::parse_from_str(s, fmt) {
16            return Some(n.and_utc());
17        }
18    }
19    None
20}
21
22#[cfg(test)]
23mod tests {
24    use super::*;
25
26    #[test]
27    fn rfc3339_z() {
28        assert!(parse_ts("2026-05-01T10:00:00Z").is_some());
29        assert!(parse_ts("2026-05-01T10:00:00.123+02:00").is_some());
30    }
31
32    #[test]
33    fn naive_is_utc() {
34        let a = parse_ts("2026-05-01 10:00:00").unwrap();
35        let b = parse_ts("2026-05-01T10:00:00Z").unwrap();
36        assert_eq!(a, b);
37    }
38
39    #[test]
40    fn garbage_is_none() {
41        assert!(parse_ts("nope").is_none());
42    }
43}