Skip to main content

nt_time/file_time/
duration.rs

1// SPDX-FileCopyrightText: 2026 Shun Sakai
2//
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5//! Implementations of conversions between [`FileTime`] and [`Duration`].
6
7use core::time::Duration;
8
9use super::FileTime;
10use crate::error::{FileTimeRangeError, FileTimeRangeErrorKind};
11
12impl FileTime {
13    /// Returns this `FileTime` as a [`Duration`] since
14    /// [`FileTime::NT_TIME_EPOCH`].
15    ///
16    /// # Examples
17    ///
18    /// ```
19    /// # use core::time::Duration;
20    /// #
21    /// # use nt_time::FileTime;
22    /// #
23    /// assert_eq!(FileTime::NT_TIME_EPOCH.to_duration(), Duration::ZERO);
24    /// assert_eq!(
25    ///     FileTime::UNIX_EPOCH.to_duration(),
26    ///     Duration::from_hours(3_234_576)
27    /// );
28    /// assert_eq!(
29    ///     FileTime::SIGNED_MAX.to_duration(),
30    ///     Duration::new(922_337_203_685, 477_580_700)
31    /// );
32    /// assert_eq!(
33    ///     FileTime::MAX.to_duration(),
34    ///     Duration::new(1_844_674_407_370, 955_161_500)
35    /// );
36    /// ```
37    #[must_use]
38    pub fn to_duration(self) -> Duration {
39        Duration::from_nanos_u128(u128::from(self.to_raw()) * 100)
40    }
41
42    /// Creates a `FileTime` from a [`Duration`] since
43    /// [`FileTime::NT_TIME_EPOCH`].
44    ///
45    /// # Errors
46    ///
47    /// Returns [`Err`] if `duration` is greater than [`FileTime::MAX`].
48    ///
49    /// # Examples
50    ///
51    /// ```
52    /// # use core::time::Duration;
53    /// #
54    /// # use nt_time::FileTime;
55    /// #
56    /// assert_eq!(
57    ///     FileTime::from_duration(Duration::ZERO),
58    ///     Ok(FileTime::NT_TIME_EPOCH)
59    /// );
60    /// assert_eq!(
61    ///     FileTime::from_duration(Duration::from_hours(3_234_576)),
62    ///     Ok(FileTime::UNIX_EPOCH)
63    /// );
64    /// assert_eq!(
65    ///     FileTime::from_duration(Duration::new(922_337_203_685, 477_580_700)),
66    ///     Ok(FileTime::SIGNED_MAX)
67    /// );
68    /// assert_eq!(
69    ///     FileTime::from_duration(Duration::new(1_844_674_407_370, 955_161_500)),
70    ///     Ok(FileTime::MAX)
71    /// );
72    ///
73    /// // After `+60056-05-28 05:36:10.955161500 UTC`.
74    /// assert!(FileTime::from_duration(Duration::new(1_844_674_407_370, 955_161_600)).is_err());
75    /// ```
76    pub fn from_duration(duration: Duration) -> Result<Self, FileTimeRangeError> {
77        let ft = u64::try_from(duration.as_nanos() / 100)
78            .map_err(|_| FileTimeRangeErrorKind::Overflow)?;
79        let ft = Self::new(ft);
80        Ok(ft)
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::{super::FILE_TIMES_PER_SEC, *};
87
88    #[test]
89    fn to_duration() {
90        assert_eq!(FileTime::NT_TIME_EPOCH.to_duration(), Duration::ZERO);
91        assert_eq!(FileTime::new(1).to_duration(), Duration::from_nanos(100));
92        assert_eq!(
93            FileTime::new(FILE_TIMES_PER_SEC - 1).to_duration(),
94            Duration::from_nanos(999_999_900)
95        );
96        assert_eq!(
97            FileTime::new(FILE_TIMES_PER_SEC).to_duration(),
98            Duration::from_secs(1)
99        );
100        assert_eq!(
101            (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_duration(),
102            Duration::new(11_644_473_599, 999_999_900)
103        );
104        assert_eq!(
105            FileTime::UNIX_EPOCH.to_duration(),
106            Duration::from_hours(3_234_576)
107        );
108        assert_eq!(
109            (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_duration(),
110            Duration::new(11_644_473_600, 100)
111        );
112        assert_eq!(
113            FileTime::SIGNED_MAX.to_duration(),
114            Duration::new(922_337_203_685, 477_580_700)
115        );
116        assert_eq!(
117            (FileTime::MAX - Duration::from_nanos(100)).to_duration(),
118            Duration::new(1_844_674_407_370, 955_161_400)
119        );
120        assert_eq!(
121            FileTime::MAX.to_duration(),
122            Duration::new(1_844_674_407_370, 955_161_500)
123        );
124    }
125
126    #[test]
127    fn from_duration() {
128        assert_eq!(
129            FileTime::from_duration(Duration::ZERO).unwrap(),
130            FileTime::NT_TIME_EPOCH
131        );
132        assert_eq!(
133            FileTime::from_duration(Duration::from_nanos(1)).unwrap(),
134            FileTime::NT_TIME_EPOCH
135        );
136        assert_eq!(
137            FileTime::from_duration(Duration::from_nanos(99)).unwrap(),
138            FileTime::NT_TIME_EPOCH
139        );
140        assert_eq!(
141            FileTime::from_duration(Duration::from_nanos(100)).unwrap(),
142            FileTime::new(1)
143        );
144        assert_eq!(
145            FileTime::from_duration(Duration::from_nanos(999_999_900)).unwrap(),
146            FileTime::new(FILE_TIMES_PER_SEC - 1)
147        );
148        assert_eq!(
149            FileTime::from_duration(Duration::from_nanos(999_999_901)).unwrap(),
150            FileTime::new(FILE_TIMES_PER_SEC - 1)
151        );
152        assert_eq!(
153            FileTime::from_duration(Duration::from_nanos(999_999_999)).unwrap(),
154            FileTime::new(FILE_TIMES_PER_SEC - 1)
155        );
156        assert_eq!(
157            FileTime::from_duration(Duration::from_secs(1)).unwrap(),
158            FileTime::new(FILE_TIMES_PER_SEC)
159        );
160        assert_eq!(
161            FileTime::from_duration(Duration::new(11_644_473_599, 999_999_900)).unwrap(),
162            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
163        );
164        assert_eq!(
165            FileTime::from_duration(Duration::new(11_644_473_599, 999_999_901)).unwrap(),
166            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
167        );
168        assert_eq!(
169            FileTime::from_duration(Duration::new(11_644_473_599, 999_999_999)).unwrap(),
170            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
171        );
172        assert_eq!(
173            FileTime::from_duration(Duration::from_hours(3_234_576)).unwrap(),
174            FileTime::UNIX_EPOCH
175        );
176        assert_eq!(
177            FileTime::from_duration(Duration::new(11_644_473_600, 1)).unwrap(),
178            FileTime::UNIX_EPOCH
179        );
180        assert_eq!(
181            FileTime::from_duration(Duration::new(11_644_473_600, 99)).unwrap(),
182            FileTime::UNIX_EPOCH
183        );
184        assert_eq!(
185            FileTime::from_duration(Duration::new(11_644_473_600, 100)).unwrap(),
186            FileTime::UNIX_EPOCH + Duration::from_nanos(100)
187        );
188        assert_eq!(
189            FileTime::from_duration(Duration::new(922_337_203_685, 477_580_700)).unwrap(),
190            FileTime::SIGNED_MAX
191        );
192        assert_eq!(
193            FileTime::from_duration(Duration::new(1_844_674_407_370, 955_161_500)).unwrap(),
194            FileTime::MAX
195        );
196    }
197
198    #[test]
199    fn from_duration_with_too_big_date_time() {
200        assert_eq!(
201            FileTime::from_duration(Duration::new(1_844_674_407_370, 955_161_600)).unwrap_err(),
202            FileTimeRangeErrorKind::Overflow.into()
203        );
204        assert_eq!(
205            FileTime::from_duration(Duration::MAX).unwrap_err(),
206            FileTimeRangeErrorKind::Overflow.into()
207        );
208    }
209}