///|
/// Gives the current instant. The core never reads the system clock; callers
/// supply a clock, so results are deterministic.
pub(open) trait Clock {
fn now(Self) -> Instant
}
///|
/// A clock that always gives the same instant, for tests and reproducible runs.
pub(all) struct FixedClock {
instant : Instant
} derive(Eq, Debug)
///|
pub fn FixedClock::FixedClock(instant : Instant) -> FixedClock {
{ instant, }
}
///|
/// A fixed clock from an ISO 8601 datetime or a `YYYY-MM-DD` date. Raises
/// `InvalidInstant` when the text does not parse.
pub fn FixedClock::at(text : String) -> FixedClock raise ValueError {
match Instant::parse(text, date_only=true) {
Some(instant) => { instant, }
None => raise InvalidInstant(text)
}
}
///|
pub impl Clock for FixedClock with fn now(self) {
self.instant
}
///|
/// The calendar date of an instant in UTC, as `YYYY-MM-DD`.
pub fn Instant::date_text(self : Instant) -> String {
let days = if self.millis >= 0L {
self.millis / 86400000L
} else {
(self.millis - 86399999L) / 86400000L
}
let (y, m, d) = civil_from_days(days)
let pad = (n : Int32, w : Int32) => {
let s = n.to_string()
"0".repeat(w - s.length()) + s
}
"\{pad(y, 4)}-\{pad(m, 2)}-\{pad(d, 2)}"
}
///|
fn civil_from_days(days : Int64) -> (Int32, Int32, Int32) {
let z = days + 719468L
let era = (if z >= 0L { z } else { z - 146096L }) / 146097L
let doe = z - era * 146097L
let yoe = (doe - doe / 1460L + doe / 36524L - doe / 146096L) / 365L
let y = yoe + era * 400L
let doy = doe - (365L * yoe + yoe / 4L - yoe / 100L)
let mp = (5L * doy + 2L) / 153L
let d = doy - (153L * mp + 2L) / 5L + 1L
let m = if mp < 10L { mp + 3L } else { mp - 9L }
let y = if m <= 2L { y + 1L } else { y }
(y.to_int(), m.to_int(), d.to_int())
}
///|
pub extend FixedClock with Eq::{not_equal, equal}
///|
pub extend FixedClock with @debug.Debug::{to_repr}
///|
pub extend FixedClock with Clock::{now}