use std::time::{Duration, SystemTime, UNIX_EPOCH};
use windows_core::Win32::Foundation::FILETIME;
const FILETIME_NS_PER_TICK: u64 = 100;
const FILETIME_TICKS_PER_SECOND: u64 = 10_000_000;
const FILETIME_UNIX_EPOCH_OFFSET_TICKS: u64 = 116_444_736_000_000_000;
pub(crate) fn try_filetime_to_system_time(filetime: FILETIME) -> Option<SystemTime> {
let ticks = (u64::from(filetime.dwHighDateTime) << 32) | u64::from(filetime.dwLowDateTime);
let (after_unix_epoch, delta_ticks) = if ticks >= FILETIME_UNIX_EPOCH_OFFSET_TICKS {
(true, ticks - FILETIME_UNIX_EPOCH_OFFSET_TICKS)
} else {
(false, FILETIME_UNIX_EPOCH_OFFSET_TICKS - ticks)
};
let delta = Duration::new(
delta_ticks / FILETIME_TICKS_PER_SECOND,
((delta_ticks % FILETIME_TICKS_PER_SECOND) * FILETIME_NS_PER_TICK) as u32,
);
if after_unix_epoch {
UNIX_EPOCH.checked_add(delta)
} else {
UNIX_EPOCH.checked_sub(delta)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_filetime_unix_epoch() {
let filetime = FILETIME {
dwLowDateTime: 3_577_643_008,
dwHighDateTime: 27_111_902,
};
assert_eq!(try_filetime_to_system_time(filetime), Some(UNIX_EPOCH));
}
#[test]
fn test_filetime_after_unix_epoch() {
let filetime = FILETIME {
dwLowDateTime: 1_057_701_854,
dwHighDateTime: 31_252_986,
};
let expected = UNIX_EPOCH + Duration::new(1_778_581_783, 4_771_000);
assert_eq!(try_filetime_to_system_time(filetime), Some(expected));
}
}