///|
/// Converts a proleptic Gregorian calendar date into a day count relative to
/// the Unix epoch (`1970-01-01` is day `0`). `month` and `day` are not range
/// checked; callers are responsible for validating the input.
///
/// Closed-form algorithm (no lookup table), following Neri and Schneider,
/// "Euclidean Affine Functions and Applications to Calendar Algorithms"
/// (as also used by Howard Hinnant's `days_from_civil`).
fn days_from_civil(year : Int, month : Int, day : Int) -> Int {
days_from_civil64(year.to_int64(), month, day).to_int()
}
///|
/// `days_from_civil` with a 64-bit year and day count, so a caller checking a
/// computed year against `NaiveDate`'s range never wraps on the way.
fn days_from_civil64(year : Int64, month : Int, day : Int) -> Int64 {
let y = if month <= 2 { year - 1L } else { year }
let era = (if y >= 0L { y } else { y - 399L }) / 400L
let yoe = y - era * 400L
let mp = (if month > 2 { month - 3 } else { month + 9 }).to_int64()
let doy = (153L * mp + 2L) / 5L + day.to_int64() - 1L
let doe = yoe * 365L + yoe / 4L - yoe / 100L + doy
era * 146097L + doe - 719468L
}
///|
/// Converts a day count relative to the Unix epoch (`1970-01-01` is day `0`)
/// back into a proleptic Gregorian `(year, month, day)` triple. Inverse of
/// `days_from_civil`.
fn civil_from_days(days : Int) -> (Int, Int, Int) {
let z = days + 719468
let era = (if z >= 0 { z } else { z - 146096 }) / 146097
let doe = z - era * 146097
let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365
let y = yoe + era * 400
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 }
(if month <= 2 { y + 1 } else { y }, month, day)
}