chadtmiller.com/atproto
atproto's primitives in Rust, small and free of I/O
atproto 0.1.1 Latest 1 package
0
0
//! Times as atproto writes them: ISO 8601 in UTC, to the millisecond.
use std::time::{SystemTime, UNIX_EPOCH};
/// Milliseconds since 1970.
pub fn now_millis() -> i64 {
let since = SystemTime::now().duration_since(UNIX_EPOCH);
since.expect("after 1970").as_millis() as i64
}
/// `millis` since 1970 as `2026-11-03T21:14:28.123Z`.
pub fn iso(millis: i64) -> String {
let (days, ms) = (millis.div_euclid(86_400_000), millis.rem_euclid(86_400_000));
// Howard Hinnant's days_to_civil, for the proleptic Gregorian calendar.
let z = days + 719_468;
let era = z.div_euclid(146_097);
let doe = z.rem_euclid(146_097);
let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365;
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
let mp = (5 * doy + 2) / 153;
let day = doy - (153 * mp + 2) / 5 + 1;
let month = if mp < 10 { mp + 3 } else { mp - 9 };
let year = yoe + era * 400 + i64::from(month <= 2);
let (h, m, s, f) = (ms / 3_600_000, ms / 60_000 % 60, ms / 1000 % 60, ms % 1000);
format!("{year:04}-{month:02}-{day:02}T{h:02}:{m:02}:{s:02}.{f:03}Z")
}