pub mod naive_date {
use ::chrono::{Datelike, NaiveDate};
pub const ENCODED_LEN: usize = 4;
pub fn to_orderable_bytes(d: &NaiveDate) -> [u8; ENCODED_LEN] {
let biased = (d.num_days_from_ce() as u32) ^ (1u32 << 31);
biased.to_be_bytes()
}
#[cfg(test)]
mod tests {
use super::*;
fn ymd(year: i32, month: u32, day: u32) -> NaiveDate {
NaiveDate::from_ymd_opt(year, month, day).unwrap()
}
#[test]
fn year_one_biases_to_known_u32() {
assert_eq!(to_orderable_bytes(&ymd(1, 1, 1)), [0x80, 0x00, 0x00, 0x01]);
}
#[test]
fn byte_order_matches_chronological_order() {
let ascending = [
NaiveDate::MIN,
ymd(-10000, 1, 1),
ymd(-1, 12, 31),
ymd(1, 1, 1),
ymd(1970, 1, 1),
ymd(2000, 1, 1),
ymd(2026, 4, 29),
ymd(10000, 1, 1),
NaiveDate::MAX,
];
for window in ascending.windows(2) {
let a = to_orderable_bytes(&window[0]);
let b = to_orderable_bytes(&window[1]);
assert!(
a < b,
"to_orderable_bytes({}) < to_orderable_bytes({}) failed",
window[0],
window[1]
);
}
}
}
}
pub mod datetime_utc {
use ::chrono::{DateTime, Utc};
pub const ENCODED_LEN: usize = 12;
pub fn to_orderable_bytes(dt: &DateTime<Utc>) -> [u8; ENCODED_LEN] {
let secs = dt.timestamp();
let nanos = dt.timestamp_subsec_nanos();
let secs_biased = (secs as u64) ^ (1u64 << 63);
let mut out = [0u8; ENCODED_LEN];
out[..8].copy_from_slice(&secs_biased.to_be_bytes());
out[8..].copy_from_slice(&nanos.to_be_bytes());
out
}
#[cfg(test)]
mod tests {
use super::*;
use ::chrono::TimeZone;
fn dt(secs: i64, nanos: u32) -> DateTime<Utc> {
Utc.timestamp_opt(secs, nanos).single().unwrap()
}
#[test]
fn unix_epoch_canonical_bytes() {
assert_eq!(
to_orderable_bytes(&dt(0, 0)),
[0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
);
}
#[test]
fn byte_order_matches_chronological_order() {
let ascending = [
DateTime::<Utc>::MIN_UTC,
dt(-1_000_000_000_000, 0),
dt(-1_000_000_000, 0),
dt(-1, 999_999_999),
dt(0, 0),
dt(0, 1),
dt(100, 100),
dt(100, 200),
dt(101, 0),
dt(1_000_000_000, 0),
dt(1_000_000_000_000, 0),
DateTime::<Utc>::MAX_UTC,
];
for window in ascending.windows(2) {
let a = to_orderable_bytes(&window[0]);
let b = to_orderable_bytes(&window[1]);
assert!(
a < b,
"to_orderable_bytes({}) < to_orderable_bytes({}) failed",
window[0],
window[1]
);
}
}
}
}