const FILETIME_TO_UNIX_100NS: i128 = 116_444_736_000_000_000;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Filetime(pub u64);
impl Filetime {
#[must_use]
pub fn from_le(bytes: &[u8; 8]) -> Self {
Filetime(u64::from_le_bytes(*bytes))
}
#[must_use]
pub fn is_zero(&self) -> bool {
self.0 == 0
}
#[must_use]
pub fn to_unix_seconds(&self) -> i64 {
let ticks_since_unix = i128::from(self.0) - FILETIME_TO_UNIX_100NS;
(ticks_since_unix / 10_000_000) as i64
}
#[must_use]
pub fn to_unix_nanos(&self) -> i128 {
(i128::from(self.0) - FILETIME_TO_UNIX_100NS) * 100
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn zero_is_unset() {
assert!(Filetime(0).is_zero());
assert!(!Filetime(1).is_zero());
}
#[test]
fn filetime_epoch_maps_to_unix_zero() {
assert_eq!(Filetime(116_444_736_000_000_000).to_unix_seconds(), 0);
}
#[test]
fn known_date_converts() {
let ft = Filetime(129_067_776_000_000_000);
assert_eq!(ft.to_unix_seconds(), 1_262_304_000);
}
#[test]
fn pre_unix_epoch_is_negative() {
let ft = Filetime(116_444_736_000_000_000 - 10_000_000);
assert_eq!(ft.to_unix_seconds(), -1);
}
#[test]
fn nanos_granularity() {
let ft = Filetime(116_444_736_000_000_000 + 1);
assert_eq!(ft.to_unix_nanos(), 100);
}
#[test]
fn from_le_reads_little_endian() {
let ft = Filetime::from_le(&1u64.to_le_bytes());
assert_eq!(ft.0, 1);
}
}