use std::time::{SystemTime, UNIX_EPOCH};
pub fn now_rfc3339() -> String {
let secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs() as i64)
.unwrap_or(0);
rfc3339_from_unix(secs)
}
pub fn rfc3339_from_unix(secs: i64) -> String {
let days = secs.div_euclid(86_400);
let rem = secs.rem_euclid(86_400);
let (year, month, day) = civil_from_days(days);
let (h, m, s) = (rem / 3600, (rem % 3600) / 60, rem % 60);
format!("{year:04}-{month:02}-{day:02}T{h:02}:{m:02}:{s:02}Z")
}
fn civil_from_days(z: i64) -> (i64, u32, u32) {
let z = z + 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 y = yoe + era * 400;
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
let mp = (5 * doy + 2) / 153;
let d = (doy - (153 * mp + 2) / 5 + 1) as u32;
let m = if mp < 10 { mp + 3 } else { mp - 9 } as u32;
(if m <= 2 { y + 1 } else { y }, m, d)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn known_instants_format_correctly() {
assert_eq!(rfc3339_from_unix(0), "1970-01-01T00:00:00Z");
assert_eq!(rfc3339_from_unix(1_000_000_000), "2001-09-09T01:46:40Z");
assert_eq!(rfc3339_from_unix(1_709_164_800), "2024-02-29T00:00:00Z");
}
#[test]
fn the_clock_produces_a_plausible_timestamp() {
let now = now_rfc3339();
assert_eq!(now.len(), 20);
assert!(now.ends_with('Z'));
assert!(now.starts_with("20"), "unexpected year in {now}");
}
}