pub fn civil_from_days(days_since_epoch: u64) -> (u64, u32, u32) {
let z = days_since_epoch + 719_468;
let era = z / 146_097; let day_of_era = z % 146_097;
let year_of_era =
(day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365; let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
let month_prime = (5 * day_of_year + 2) / 153; let day = day_of_year - (153 * month_prime + 2) / 5 + 1; let month = if month_prime < 10 {
month_prime + 3
} else {
month_prime - 9
}; let year = year_of_era + era * 400 + if month <= 2 { 1 } else { 0 };
(year, month as u32, day as u32)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn civil_from_days_epoch() {
assert_eq!(civil_from_days(0), (1970, 1, 1));
}
#[test]
fn civil_from_days_first_of_february() {
assert_eq!(civil_from_days(31), (1970, 2, 1));
}
#[test]
fn civil_from_days_leap_day_2024() {
assert_eq!(civil_from_days(19_782), (2024, 2, 29));
}
#[test]
fn civil_from_days_leap_day_2000() {
assert_eq!(civil_from_days(11_016), (2000, 2, 29));
}
#[test]
fn civil_from_days_not_a_leap_day_2100() {
assert_eq!(civil_from_days(47_540), (2100, 2, 28));
}
}