use crate::PosixNs;
#[must_use]
pub fn filetime(ft: u64) -> Option<i64> {
let low = (ft & 0xFFFF_FFFF) as u32;
let high = (ft >> 32) as u32;
crate::compose::filetime_hilo(low, high)
.ok()
.map(PosixNs::unix_seconds)
}
#[must_use]
pub fn civil(year: i32, month: u32, day: u32, hour: u32, minute: u32, second: u32) -> Option<i64> {
let date = jiff::civil::Date::new(
i16::try_from(year).ok()?,
i8::try_from(month).ok()?,
i8::try_from(day).ok()?,
)
.ok()?;
let time = jiff::civil::Time::new(
i8::try_from(hour).ok()?,
i8::try_from(minute).ok()?,
i8::try_from(second).ok()?,
0,
)
.ok()?;
date.to_datetime(time)
.to_zoned(jiff::tz::TimeZone::UTC)
.ok()
.map(|z| z.timestamp().as_second())
}
#[cfg(test)]
mod tests {
use super::{civil, filetime};
use crate::PosixNs;
#[test]
fn posix_ns_to_unix_seconds_floors() {
assert_eq!(PosixNs(0).unix_seconds(), 0);
assert_eq!(PosixNs(1_000_000_000).unix_seconds(), 1);
assert_eq!(PosixNs(1_500_000_000).unix_seconds(), 1); assert_eq!(PosixNs(-1_000_000_000).unix_seconds(), -1);
assert_eq!(PosixNs(-500_000_000).unix_seconds(), -1); }
#[test]
fn filetime_epoch_offset_is_unix_zero() {
assert_eq!(filetime(116_444_736_000_000_000), Some(0));
}
#[test]
fn filetime_known_value() {
assert_eq!(filetime(125_911_584_000_000_000), Some(946_684_800));
}
#[test]
fn filetime_pre_1970_still_decodes_negative() {
assert_eq!(filetime(0), Some(-11_644_473_600));
}
#[test]
fn civil_known_dates() {
assert_eq!(civil(1970, 1, 1, 0, 0, 0), Some(0));
assert_eq!(civil(2000, 1, 1, 0, 0, 0), Some(946_684_800));
assert_eq!(civil(2021, 3, 1, 12, 30, 15), Some(1_614_601_815));
}
#[test]
fn civil_out_of_range_is_none_not_panic() {
assert_eq!(civil(2021, 13, 1, 0, 0, 0), None); assert_eq!(civil(2021, 2, 30, 0, 0, 0), None); assert_eq!(civil(i32::MAX, 1, 1, 0, 0, 0), None); }
}