const MILLISECONDS_PER_DAY: i64 = 86_400_000;
pub fn civil_from_days(days: i64) -> (i64, u32, u32) {
let shifted: i64 = days + 719_468;
let era: i64 = shifted.div_euclid(146_097);
let day_of_era: i64 = shifted.rem_euclid(146_097);
let year_of_era: i64 =
(day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
let day_of_year: i64 = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
let month_index: i64 = (5 * day_of_year + 2) / 153;
let day: i64 = day_of_year - (153 * month_index + 2) / 5 + 1;
let month: i64 = if month_index < 10 {
month_index + 3
} else {
month_index - 9
};
let year: i64 = year_of_era + era * 400 + i64::from(month <= 2);
return (year, month as u32, day as u32);
}
pub fn format_iso_milliseconds(milliseconds: i64) -> String {
let days: i64 = milliseconds.div_euclid(MILLISECONDS_PER_DAY);
let within: i64 = milliseconds.rem_euclid(MILLISECONDS_PER_DAY);
let (year, month, day) = civil_from_days(days);
let hours: i64 = within / 3_600_000;
let minutes: i64 = within / 60_000 % 60;
let seconds: i64 = within / 1000 % 60;
let millis: i64 = within % 1000;
return format!(
"{year:04}-{month:02}-{day:02}T{hours:02}:{minutes:02}:{seconds:02}.{millis:03}Z"
);
}
pub fn now_iso() -> String {
let elapsed: std::time::Duration = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default();
let milliseconds: i64 = i64::try_from(elapsed.as_millis()).unwrap_or(i64::MAX);
return format_iso_milliseconds(milliseconds);
}
#[cfg(test)]
#[path = "iso_time_tests.rs"]
mod tests;