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        Ok(Self::new(ft))
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::{super::FILE_TIMES_PER_SEC, *};
86
87    #[test]
88    fn to_duration() {
89        assert_eq!(FileTime::NT_TIME_EPOCH.to_duration(), Duration::ZERO);
90        assert_eq!(FileTime::new(1).to_duration(), Duration::from_nanos(100));
91        assert_eq!(
92            FileTime::new(FILE_TIMES_PER_SEC - 1).to_duration(),
93            Duration::from_nanos(999_999_900)
94        );
95        assert_eq!(
96            FileTime::new(FILE_TIMES_PER_SEC).to_duration(),
97            Duration::from_secs(1)
98        );
99        assert_eq!(
100            (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_duration(),
101            Duration::new(11_644_473_599, 999_999_900)
102        );
103        assert_eq!(
104            FileTime::UNIX_EPOCH.to_duration(),
105            Duration::from_hours(3_234_576)
106        );
107        assert_eq!(
108            (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_duration(),
109            Duration::new(11_644_473_600, 100)
110        );
111        assert_eq!(
112            FileTime::SIGNED_MAX.to_duration(),
113            Duration::new(922_337_203_685, 477_580_700)
114        );
115        assert_eq!(
116            (FileTime::MAX - Duration::from_nanos(100)).to_duration(),
117            Duration::new(1_844_674_407_370, 955_161_400)
118        );
119        assert_eq!(
120            FileTime::MAX.to_duration(),
121            Duration::new(1_844_674_407_370, 955_161_500)
122        );
123    }
124
125    #[test]
126    fn from_duration() {
127        assert_eq!(
128            FileTime::from_duration(Duration::ZERO).unwrap(),
129            FileTime::NT_TIME_EPOCH
130        );
131        assert_eq!(
132            FileTime::from_duration(Duration::from_nanos(1)).unwrap(),
133            FileTime::NT_TIME_EPOCH
134        );
135        assert_eq!(
136            FileTime::from_duration(Duration::from_nanos(99)).unwrap(),
137            FileTime::NT_TIME_EPOCH
138        );
139        assert_eq!(
140            FileTime::from_duration(Duration::from_nanos(100)).unwrap(),
141            FileTime::new(1)
142        );
143        assert_eq!(
144            FileTime::from_duration(Duration::from_nanos(999_999_900)).unwrap(),
145            FileTime::new(FILE_TIMES_PER_SEC - 1)
146        );
147        assert_eq!(
148            FileTime::from_duration(Duration::from_nanos(999_999_901)).unwrap(),
149            FileTime::new(FILE_TIMES_PER_SEC - 1)
150        );
151        assert_eq!(
152            FileTime::from_duration(Duration::from_nanos(999_999_999)).unwrap(),
153            FileTime::new(FILE_TIMES_PER_SEC - 1)
154        );
155        assert_eq!(
156            FileTime::from_duration(Duration::from_secs(1)).unwrap(),
157            FileTime::new(FILE_TIMES_PER_SEC)
158        );
159        assert_eq!(
160            FileTime::from_duration(Duration::new(11_644_473_599, 999_999_900)).unwrap(),
161            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
162        );
163        assert_eq!(
164            FileTime::from_duration(Duration::new(11_644_473_599, 999_999_901)).unwrap(),
165            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
166        );
167        assert_eq!(
168            FileTime::from_duration(Duration::new(11_644_473_599, 999_999_999)).unwrap(),
169            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
170        );
171        assert_eq!(
172            FileTime::from_duration(Duration::from_hours(3_234_576)).unwrap(),
173            FileTime::UNIX_EPOCH
174        );
175        assert_eq!(
176            FileTime::from_duration(Duration::new(11_644_473_600, 1)).unwrap(),
177            FileTime::UNIX_EPOCH
178        );
179        assert_eq!(
180            FileTime::from_duration(Duration::new(11_644_473_600, 99)).unwrap(),
181            FileTime::UNIX_EPOCH
182        );
183        assert_eq!(
184            FileTime::from_duration(Duration::new(11_644_473_600, 100)).unwrap(),
185            FileTime::UNIX_EPOCH + Duration::from_nanos(100)
186        );
187        assert_eq!(
188            FileTime::from_duration(Duration::new(922_337_203_685, 477_580_700)).unwrap(),
189            FileTime::SIGNED_MAX
190        );
191        assert_eq!(
192            FileTime::from_duration(Duration::new(1_844_674_407_370, 955_161_500)).unwrap(),
193            FileTime::MAX
194        );
195    }
196
197    #[test]
198    fn from_duration_with_too_big_date_time() {
199        assert_eq!(
200            FileTime::from_duration(Duration::new(1_844_674_407_370, 955_161_600)).unwrap_err(),
201            FileTimeRangeErrorKind::Overflow.into()
202        );
203        assert_eq!(
204            FileTime::from_duration(Duration::MAX).unwrap_err(),
205            FileTimeRangeErrorKind::Overflow.into()
206        );
207    }
208}