1#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
3pub enum NtTimeError {
4 Negative,
5 Overflow,
6}
7
8#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
14pub struct NtTime(pub(crate) u64);
15
16impl Default for NtTime {
17 fn default() -> Self {
18 Self::NT_TIME_EPOCH
19 }
20}
21
22impl NtTime {
23 const FILE_TIMES_PER_SEC: u64 = 10_000_000;
24
25 pub const UNIX_EPOCH: NtTime = NtTime::new(134774 * 86400 * Self::FILE_TIMES_PER_SEC);
27
28 pub const NT_TIME_EPOCH: NtTime = NtTime::new(0);
30
31 #[must_use]
33 #[inline]
34 pub const fn new(ft: u64) -> Self {
35 Self(ft)
36 }
37
38 #[must_use]
40 #[inline]
41 pub fn now() -> Self {
42 use std::time::SystemTime;
43
44 SystemTime::now()
45 .try_into()
46 .expect("the current date and time is not a valid NtTime")
47 }
48
49 fn sub(self, rhs: Self) -> std::time::Duration {
50 let duration = self.0 - rhs.0;
51 std::time::Duration::new(
52 duration / Self::FILE_TIMES_PER_SEC,
53 u32::try_from((duration % Self::FILE_TIMES_PER_SEC) * 100)
54 .expect("the number of nanoseconds is not a valid `u32`"),
55 )
56 }
57}
58
59impl From<u64> for NtTime {
60 #[inline]
62 fn from(file_time: u64) -> Self {
63 Self::new(file_time)
64 }
65}
66
67impl From<NtTime> for u64 {
68 #[inline]
70 fn from(nt_time: NtTime) -> Self {
71 nt_time.0
72 }
73}
74
75impl TryFrom<i64> for NtTime {
76 type Error = NtTimeError;
77
78 #[inline]
80 fn try_from(file_time: i64) -> Result<Self, Self::Error> {
81 file_time
82 .try_into()
83 .map_err(|_| NtTimeError::Negative)
84 .map(Self::new)
85 }
86}
87
88impl From<NtTime> for std::time::SystemTime {
89 #[inline]
91 fn from(file_time: NtTime) -> Self {
92 let duration = std::time::Duration::new(
93 file_time.0 / NtTime::FILE_TIMES_PER_SEC,
94 u32::try_from((file_time.0 % NtTime::FILE_TIMES_PER_SEC) * 100)
95 .expect("the number of nanoseconds is not a valid `u32`"),
96 );
97
98 (std::time::SystemTime::UNIX_EPOCH - (NtTime::UNIX_EPOCH.sub(NtTime::NT_TIME_EPOCH)))
99 + duration
100 }
101}
102
103impl TryFrom<std::time::SystemTime> for NtTime {
104 type Error = NtTimeError;
105
106 #[inline]
108 fn try_from(st: std::time::SystemTime) -> Result<Self, Self::Error> {
109 use std::time::SystemTime;
110
111 let elapsed = st
112 .duration_since(
113 SystemTime::UNIX_EPOCH - (NtTime::UNIX_EPOCH.sub(NtTime::NT_TIME_EPOCH)),
114 )
115 .map(|d| d.as_nanos())
116 .map_err(|_| NtTimeError::Negative)?;
117
118 let file_time = u64::try_from(elapsed / 100).map_err(|_| NtTimeError::Overflow)?;
119
120 Ok(Self::new(file_time))
121 }
122}
123
124#[cfg(feature = "nt-time")]
125impl From<NtTime> for nt_time::FileTime {
126 fn from(value: NtTime) -> Self {
127 Self::new(value.0)
128 }
129}
130
131#[cfg(feature = "nt-time")]
132impl From<nt_time::FileTime> for NtTime {
133 fn from(value: nt_time::FileTime) -> Self {
134 Self::new(value.to_raw())
135 }
136}