smb_dtyp/binrw_util/
file_time.rs1use std::fmt::Display;
5use std::ops::Deref;
6use std::time::{Duration, SystemTime};
7
8use binrw::prelude::*;
9use time::PrimitiveDateTime;
10use time::macros::datetime;
11
12#[derive(BinRead, BinWrite, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
13pub struct FileTime {
14 value: u64,
16}
17
18impl FileTime {
19 const EPOCH: PrimitiveDateTime = datetime!(1601-01-01 00:00:00);
20 const SCALE_VALUE_TO_NANOS: u64 = 100;
21 const SCALE_VALUE_TO_SECS: u64 = 1_000_000_000 / Self::SCALE_VALUE_TO_NANOS;
22
23 pub fn date_time(&self) -> PrimitiveDateTime {
24 let duration = core::time::Duration::from_nanos(self.value * Self::SCALE_VALUE_TO_NANOS);
25 Self::EPOCH + duration
26 }
27}
28
29impl Display for FileTime {
30 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31 self.date_time().fmt(f)
32 }
33}
34
35impl std::fmt::Debug for FileTime {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 f.debug_tuple("FileTime").field(&self.date_time()).finish()
38 }
39}
40
41impl From<u64> for FileTime {
42 fn from(value: u64) -> Self {
43 Self { value }
44 }
45}
46
47impl From<PrimitiveDateTime> for FileTime {
48 fn from(dt: PrimitiveDateTime) -> Self {
49 let duration = dt - Self::EPOCH;
50 Self {
51 value: duration.whole_nanoseconds() as u64 / Self::SCALE_VALUE_TO_NANOS,
52 }
53 }
54}
55
56impl Deref for FileTime {
57 type Target = u64;
58
59 fn deref(&self) -> &Self::Target {
60 &self.value
61 }
62}
63
64impl From<FileTime> for SystemTime {
65 fn from(src: FileTime) -> SystemTime {
66 let epoch = SystemTime::from(FileTime::EPOCH.as_utc());
67 let secs = src.value / FileTime::SCALE_VALUE_TO_SECS;
68 let nanos = src.value % FileTime::SCALE_VALUE_TO_SECS * FileTime::SCALE_VALUE_TO_NANOS;
69 epoch + Duration::new(secs, nanos as u32)
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use time::macros::datetime;
77
78 const TEST_VAL1_U64: u64 = 133818609802776324;
79 const TEST_VAL1_DT: PrimitiveDateTime = datetime!(2025-01-20 15:36:20.277632400);
80
81 #[test]
82 pub fn test_file_time_from_u64_correct() {
83 assert_eq!(FileTime::from(TEST_VAL1_U64).date_time(), TEST_VAL1_DT);
84 let result: SystemTime = FileTime::from(TEST_VAL1_U64).into();
85 assert_eq!(time::UtcDateTime::from(result), TEST_VAL1_DT.as_utc());
86 }
87
88 #[test]
89 pub fn test_file_time_from_datetime_correct() {
90 assert_eq!(*FileTime::from(TEST_VAL1_DT), TEST_VAL1_U64)
91 }
92}