nt_time/file_time/
unix_time.rs

1// SPDX-FileCopyrightText: 2023 Shun Sakai
2//
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5//! Implementations of conversions between [`FileTime`] and [Unix time].
6//!
7//! [Unix time]: https://en.wikipedia.org/wiki/Unix_time
8
9use core::time::Duration;
10
11use super::{FILE_TIMES_PER_SEC, FileTime};
12use crate::error::{FileTimeRangeError, FileTimeRangeErrorKind};
13
14impl FileTime {
15    #[allow(clippy::missing_panics_doc)]
16    /// Returns [Unix time] represented as a pair of the number of whole seconds
17    /// and the number of additional nanoseconds, like the [`timespec`]
18    /// structure in C11, which represents the same date and time as this
19    /// `FileTime`.
20    ///
21    /// The first return value represents the number of whole seconds, and the
22    /// second return value represents the number of additional nanoseconds.
23    ///
24    /// # Examples
25    ///
26    /// ```
27    /// # use nt_time::FileTime;
28    /// #
29    /// assert_eq!(FileTime::NT_TIME_EPOCH.to_unix_time(), (-11_644_473_600, 0));
30    /// assert_eq!(FileTime::UNIX_EPOCH.to_unix_time(), (0, 0));
31    /// assert_eq!(
32    ///     FileTime::SIGNED_MAX.to_unix_time(),
33    ///     (910_692_730_085, 477_580_700)
34    /// );
35    /// assert_eq!(
36    ///     FileTime::MAX.to_unix_time(),
37    ///     (1_833_029_933_770, 955_161_500)
38    /// );
39    /// ```
40    ///
41    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
42    /// [`timespec`]: https://en.cppreference.com/w/c/chrono/timespec
43    #[must_use]
44    #[inline]
45    pub fn to_unix_time(self) -> (i64, u32) {
46        let (secs, subsec_nanos) = (
47            self.to_unix_time_secs(),
48            u32::try_from((self.to_raw() % FILE_TIMES_PER_SEC) * 100)
49                .expect("the number of nanoseconds should be in the range of `u32`"),
50        );
51        (secs, subsec_nanos)
52    }
53
54    #[allow(clippy::missing_panics_doc)]
55    /// Returns [Unix time] in seconds which represents the same date and time
56    /// as this `FileTime`.
57    ///
58    /// # Examples
59    ///
60    /// ```
61    /// # use nt_time::FileTime;
62    /// #
63    /// assert_eq!(FileTime::NT_TIME_EPOCH.to_unix_time_secs(), -11_644_473_600);
64    /// assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_secs(), 0);
65    /// assert_eq!(FileTime::SIGNED_MAX.to_unix_time_secs(), 910_692_730_085);
66    /// assert_eq!(FileTime::MAX.to_unix_time_secs(), 1_833_029_933_770);
67    /// ```
68    ///
69    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
70    #[must_use]
71    #[inline]
72    pub fn to_unix_time_secs(self) -> i64 {
73        i64::try_from(self.to_raw() / FILE_TIMES_PER_SEC)
74            .expect("the number of seconds should be in the range of `i64`")
75            - 11_644_473_600
76    }
77
78    #[allow(clippy::missing_panics_doc)]
79    /// Returns [Unix time] in milliseconds which represents the same date and
80    /// time as this `FileTime`.
81    ///
82    /// # Examples
83    ///
84    /// ```
85    /// # use nt_time::FileTime;
86    /// #
87    /// assert_eq!(
88    ///     FileTime::NT_TIME_EPOCH.to_unix_time_millis(),
89    ///     -11_644_473_600_000
90    /// );
91    /// assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_millis(), 0);
92    /// assert_eq!(
93    ///     FileTime::SIGNED_MAX.to_unix_time_millis(),
94    ///     910_692_730_085_477
95    /// );
96    /// assert_eq!(FileTime::MAX.to_unix_time_millis(), 1_833_029_933_770_955);
97    /// ```
98    ///
99    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
100    #[must_use]
101    #[inline]
102    pub fn to_unix_time_millis(self) -> i64 {
103        self.to_unix_time_nanos()
104            .div_euclid(1_000_000)
105            .try_into()
106            .expect("the number of milliseconds should be in the range of `i64`")
107    }
108
109    #[allow(clippy::missing_panics_doc)]
110    /// Returns [Unix time] in microseconds which represents the same date and
111    /// time as this `FileTime`.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// # use nt_time::FileTime;
117    /// #
118    /// assert_eq!(
119    ///     FileTime::NT_TIME_EPOCH.to_unix_time_micros(),
120    ///     -11_644_473_600_000_000
121    /// );
122    /// assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_micros(), 0);
123    /// assert_eq!(
124    ///     FileTime::SIGNED_MAX.to_unix_time_micros(),
125    ///     910_692_730_085_477_580
126    /// );
127    /// assert_eq!(
128    ///     FileTime::MAX.to_unix_time_micros(),
129    ///     1_833_029_933_770_955_161
130    /// );
131    /// ```
132    ///
133    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
134    #[must_use]
135    #[inline]
136    pub fn to_unix_time_micros(self) -> i64 {
137        self.to_unix_time_nanos()
138            .div_euclid(1000)
139            .try_into()
140            .expect("the number of microseconds should be in the range of `i64`")
141    }
142
143    /// Returns [Unix time] in nanoseconds which represents the same date and
144    /// time as this `FileTime`.
145    ///
146    /// # Examples
147    ///
148    /// ```
149    /// # use nt_time::FileTime;
150    /// #
151    /// assert_eq!(
152    ///     FileTime::NT_TIME_EPOCH.to_unix_time_nanos(),
153    ///     -11_644_473_600_000_000_000
154    /// );
155    /// assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_nanos(), 0);
156    /// assert_eq!(
157    ///     FileTime::SIGNED_MAX.to_unix_time_nanos(),
158    ///     910_692_730_085_477_580_700
159    /// );
160    /// assert_eq!(
161    ///     FileTime::MAX.to_unix_time_nanos(),
162    ///     1_833_029_933_770_955_161_500
163    /// );
164    /// ```
165    ///
166    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
167    #[must_use]
168    #[inline]
169    pub fn to_unix_time_nanos(self) -> i128 {
170        (i128::from(self.to_raw()) * 100) - 11_644_473_600_000_000_000
171    }
172
173    /// Creates a `FileTime` with the given [Unix time], represented as a pair
174    /// of the number of whole seconds and the number of additional nanoseconds,
175    /// like the [`timespec`] structure in C11.
176    ///
177    /// `secs` is the number of whole seconds, and `nanos` is the number of
178    /// additional nanoseconds.
179    ///
180    /// If the number of nanoseconds is greater than 1 billion (the number of
181    /// nanoseconds in a second), then it will carry over into the seconds
182    /// provided.
183    ///
184    /// # Errors
185    ///
186    /// Returns [`Err`] if the provided Unix time is out of range for the file
187    /// time.
188    ///
189    /// # Examples
190    ///
191    /// ```
192    /// # use core::time::Duration;
193    /// #
194    /// # use nt_time::FileTime;
195    /// #
196    /// assert_eq!(
197    ///     FileTime::from_unix_time(-11_644_473_600, 0),
198    ///     Ok(FileTime::NT_TIME_EPOCH)
199    /// );
200    /// assert_eq!(FileTime::from_unix_time(0, 0), Ok(FileTime::UNIX_EPOCH));
201    /// assert_eq!(
202    ///     FileTime::from_unix_time(910_692_730_085, 477_580_700),
203    ///     Ok(FileTime::SIGNED_MAX)
204    /// );
205    /// assert_eq!(
206    ///     FileTime::from_unix_time(1_833_029_933_770, 955_161_500),
207    ///     Ok(FileTime::MAX)
208    /// );
209    ///
210    /// // The number of nanoseconds is greater than 1 billion.
211    /// assert_eq!(
212    ///     FileTime::from_unix_time(0, 1_000_000_000),
213    ///     FileTime::from_unix_time(1, 0)
214    /// );
215    ///
216    /// // Before `1601-01-01 00:00:00 UTC`.
217    /// assert!(FileTime::from_unix_time(-11_644_473_601, 999_999_999).is_err());
218    /// // After `+60056-05-28 05:36:10.955161500 UTC`.
219    /// assert!(FileTime::from_unix_time(1_833_029_933_770, 955_161_600).is_err());
220    /// ```
221    ///
222    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
223    /// [`timespec`]: https://en.cppreference.com/w/c/chrono/timespec
224    #[inline]
225    pub fn from_unix_time(secs: i64, nanos: u32) -> Result<Self, FileTimeRangeError> {
226        Self::from_unix_time_secs(secs).and_then(|ft| {
227            ft.checked_add(Duration::from_nanos(nanos.into()))
228                .ok_or_else(|| FileTimeRangeErrorKind::Overflow.into())
229        })
230    }
231
232    /// Creates a `FileTime` with the given [Unix time] in seconds.
233    ///
234    /// # Errors
235    ///
236    /// Returns [`Err`] if `secs` is out of range for the file time.
237    ///
238    /// # Examples
239    ///
240    /// ```
241    /// # use core::time::Duration;
242    /// #
243    /// # use nt_time::FileTime;
244    /// #
245    /// assert_eq!(
246    ///     FileTime::from_unix_time_secs(-11_644_473_600),
247    ///     Ok(FileTime::NT_TIME_EPOCH)
248    /// );
249    /// assert_eq!(FileTime::from_unix_time_secs(0), Ok(FileTime::UNIX_EPOCH));
250    /// assert_eq!(
251    ///     FileTime::from_unix_time_secs(910_692_730_085),
252    ///     Ok(FileTime::SIGNED_MAX - Duration::from_nanos(477_580_700))
253    /// );
254    /// assert_eq!(
255    ///     FileTime::from_unix_time_secs(1_833_029_933_770),
256    ///     Ok(FileTime::MAX - Duration::from_nanos(955_161_500))
257    /// );
258    ///
259    /// // Before `1601-01-01 00:00:00 UTC`.
260    /// assert!(FileTime::from_unix_time_secs(-11_644_473_601).is_err());
261    /// // After `+60056-05-28 05:36:10.955161500 UTC`.
262    /// assert!(FileTime::from_unix_time_secs(1_833_029_933_771).is_err());
263    /// ```
264    ///
265    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
266    #[inline]
267    pub fn from_unix_time_secs(secs: i64) -> Result<Self, FileTimeRangeError> {
268        if secs <= 1_833_029_933_770 {
269            u64::try_from(secs + 11_644_473_600)
270                .map_err(|_| FileTimeRangeErrorKind::Negative.into())
271                .map(|t| t * FILE_TIMES_PER_SEC)
272                .map(Self::new)
273        } else {
274            Err(FileTimeRangeErrorKind::Overflow.into())
275        }
276    }
277
278    /// Creates a `FileTime` with the given [Unix time] in milliseconds.
279    ///
280    /// # Errors
281    ///
282    /// Returns [`Err`] if `millis` is out of range for the file time.
283    ///
284    /// # Examples
285    ///
286    /// ```
287    /// # use core::time::Duration;
288    /// #
289    /// # use nt_time::FileTime;
290    /// #
291    /// assert_eq!(
292    ///     FileTime::from_unix_time_millis(-11_644_473_600_000),
293    ///     Ok(FileTime::NT_TIME_EPOCH)
294    /// );
295    /// assert_eq!(FileTime::from_unix_time_millis(0), Ok(FileTime::UNIX_EPOCH));
296    /// assert_eq!(
297    ///     FileTime::from_unix_time_millis(910_692_730_085_477),
298    ///     Ok(FileTime::SIGNED_MAX - Duration::from_nanos(580_700))
299    /// );
300    /// assert_eq!(
301    ///     FileTime::from_unix_time_millis(1_833_029_933_770_955),
302    ///     Ok(FileTime::MAX - Duration::from_nanos(161_500))
303    /// );
304    ///
305    /// // Before `1601-01-01 00:00:00 UTC`.
306    /// assert!(FileTime::from_unix_time_millis(-11_644_473_600_001).is_err());
307    /// // After `+60056-05-28 05:36:10.955161500 UTC`.
308    /// assert!(FileTime::from_unix_time_millis(1_833_029_933_770_956).is_err());
309    /// ```
310    ///
311    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
312    #[inline]
313    pub fn from_unix_time_millis(millis: i64) -> Result<Self, FileTimeRangeError> {
314        let nanos = i128::from(millis) * 1_000_000;
315        Self::from_unix_time_nanos(nanos)
316    }
317
318    /// Creates a `FileTime` with the given [Unix time] in microseconds.
319    ///
320    /// # Errors
321    ///
322    /// Returns [`Err`] if `micros` is out of range for the file time.
323    ///
324    /// # Examples
325    ///
326    /// ```
327    /// # use core::time::Duration;
328    /// #
329    /// # use nt_time::FileTime;
330    /// #
331    /// assert_eq!(
332    ///     FileTime::from_unix_time_micros(-11_644_473_600_000_000),
333    ///     Ok(FileTime::NT_TIME_EPOCH)
334    /// );
335    /// assert_eq!(FileTime::from_unix_time_micros(0), Ok(FileTime::UNIX_EPOCH));
336    /// assert_eq!(
337    ///     FileTime::from_unix_time_micros(910_692_730_085_477_580),
338    ///     Ok(FileTime::SIGNED_MAX - Duration::from_nanos(700))
339    /// );
340    /// assert_eq!(
341    ///     FileTime::from_unix_time_micros(1_833_029_933_770_955_161),
342    ///     Ok(FileTime::MAX - Duration::from_nanos(500))
343    /// );
344    ///
345    /// // Before `1601-01-01 00:00:00 UTC`.
346    /// assert!(FileTime::from_unix_time_micros(-11_644_473_600_000_001).is_err());
347    /// // After `+60056-05-28 05:36:10.955161500 UTC`.
348    /// assert!(FileTime::from_unix_time_micros(1_833_029_933_770_955_162).is_err());
349    /// ```
350    ///
351    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
352    #[inline]
353    pub fn from_unix_time_micros(micros: i64) -> Result<Self, FileTimeRangeError> {
354        let nanos = i128::from(micros) * 1000;
355        Self::from_unix_time_nanos(nanos)
356    }
357
358    /// Creates a `FileTime` with the given [Unix time] in nanoseconds.
359    ///
360    /// # Errors
361    ///
362    /// Returns [`Err`] if `nanos` is out of range for the file time.
363    ///
364    /// # Examples
365    ///
366    /// ```
367    /// # use nt_time::FileTime;
368    /// #
369    /// assert_eq!(
370    ///     FileTime::from_unix_time_nanos(-11_644_473_600_000_000_000),
371    ///     Ok(FileTime::NT_TIME_EPOCH)
372    /// );
373    /// assert_eq!(FileTime::from_unix_time_nanos(0), Ok(FileTime::UNIX_EPOCH));
374    /// assert_eq!(
375    ///     FileTime::from_unix_time_nanos(910_692_730_085_477_580_700),
376    ///     Ok(FileTime::SIGNED_MAX)
377    /// );
378    /// assert_eq!(
379    ///     FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_500),
380    ///     Ok(FileTime::MAX)
381    /// );
382    ///
383    /// // Before `1601-01-01 00:00:00 UTC`.
384    /// assert!(FileTime::from_unix_time_nanos(-11_644_473_600_000_000_001).is_err());
385    /// // After `+60056-05-28 05:36:10.955161500 UTC`.
386    /// assert!(FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_501).is_err());
387    /// ```
388    ///
389    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
390    #[inline]
391    pub fn from_unix_time_nanos(nanos: i128) -> Result<Self, FileTimeRangeError> {
392        if nanos <= 1_833_029_933_770_955_161_500 {
393            (nanos + 11_644_473_600_000_000_000)
394                .div_euclid(100)
395                .try_into()
396                .map_err(|_| FileTimeRangeErrorKind::Negative.into())
397                .map(Self::new)
398        } else {
399            Err(FileTimeRangeErrorKind::Overflow.into())
400        }
401    }
402}
403
404#[cfg(test)]
405mod tests {
406    use super::*;
407
408    const NANOS_PER_SEC: u32 = 1_000_000_000;
409
410    #[test]
411    fn to_unix_time() {
412        assert_eq!(
413            FileTime::NT_TIME_EPOCH.to_unix_time(),
414            (-11_644_473_600, u32::MIN)
415        );
416        assert_eq!(FileTime::new(1).to_unix_time(), (-11_644_473_600, 100));
417        assert_eq!(
418            FileTime::new(FILE_TIMES_PER_SEC - 1).to_unix_time(),
419            (-11_644_473_600, NANOS_PER_SEC - 100)
420        );
421        assert_eq!(
422            FileTime::new(FILE_TIMES_PER_SEC).to_unix_time(),
423            (-11_644_473_599, u32::MIN)
424        );
425        assert_eq!(
426            (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time(),
427            (i64::default() - 1, NANOS_PER_SEC - 100)
428        );
429        assert_eq!(
430            FileTime::UNIX_EPOCH.to_unix_time(),
431            (i64::default(), u32::MIN)
432        );
433        assert_eq!(
434            (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time(),
435            (i64::default(), 100)
436        );
437        assert_eq!(
438            FileTime::SIGNED_MAX.to_unix_time(),
439            (910_692_730_085, 477_580_700)
440        );
441        assert_eq!(
442            (FileTime::MAX - Duration::from_nanos(100)).to_unix_time(),
443            (1_833_029_933_770, 955_161_400)
444        );
445        assert_eq!(
446            FileTime::MAX.to_unix_time(),
447            (1_833_029_933_770, 955_161_500)
448        );
449    }
450
451    #[cfg(feature = "std")]
452    #[test_strategy::proptest]
453    fn to_unix_time_roundtrip(ft: u64) {
454        use proptest::prop_assert;
455
456        let ts = FileTime::new(ft).to_unix_time();
457        prop_assert!((-11_644_473_600..=1_833_029_933_770).contains(&ts.0));
458        prop_assert!(ts.1 < NANOS_PER_SEC);
459    }
460
461    #[test]
462    fn to_unix_time_secs() {
463        assert_eq!(FileTime::NT_TIME_EPOCH.to_unix_time_secs(), -11_644_473_600);
464        assert_eq!(FileTime::new(1).to_unix_time_secs(), -11_644_473_600);
465        assert_eq!(
466            FileTime::new(FILE_TIMES_PER_SEC - 1).to_unix_time_secs(),
467            -11_644_473_600
468        );
469        assert_eq!(
470            FileTime::new(FILE_TIMES_PER_SEC).to_unix_time_secs(),
471            -11_644_473_599
472        );
473        assert_eq!(
474            (FileTime::UNIX_EPOCH - Duration::from_secs(1)).to_unix_time_secs(),
475            i64::default() - 1
476        );
477        assert_eq!(
478            (FileTime::UNIX_EPOCH - Duration::from_nanos(999_999_900)).to_unix_time_secs(),
479            i64::default() - 1
480        );
481        assert_eq!(
482            (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time_secs(),
483            i64::default() - 1
484        );
485        assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_secs(), i64::default());
486        assert_eq!(
487            (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time_secs(),
488            i64::default()
489        );
490        assert_eq!(
491            (FileTime::UNIX_EPOCH + Duration::from_nanos(999_999_900)).to_unix_time_secs(),
492            i64::default()
493        );
494        assert_eq!(
495            (FileTime::UNIX_EPOCH + Duration::from_secs(1)).to_unix_time_secs(),
496            i64::default() + 1
497        );
498        assert_eq!(FileTime::SIGNED_MAX.to_unix_time_secs(), 910_692_730_085);
499        assert_eq!(
500            (FileTime::MAX - Duration::from_nanos(955_161_600)).to_unix_time_secs(),
501            1_833_029_933_769
502        );
503        assert_eq!(
504            (FileTime::MAX - Duration::from_nanos(955_161_500)).to_unix_time_secs(),
505            1_833_029_933_770
506        );
507        assert_eq!(
508            (FileTime::MAX - Duration::from_nanos(955_161_400)).to_unix_time_secs(),
509            1_833_029_933_770
510        );
511        assert_eq!(FileTime::MAX.to_unix_time_secs(), 1_833_029_933_770);
512    }
513
514    #[cfg(feature = "std")]
515    #[test_strategy::proptest]
516    fn to_unix_time_secs_roundtrip(ft: u64) {
517        use proptest::prop_assert;
518
519        let ts = FileTime::new(ft).to_unix_time_secs();
520        prop_assert!((-11_644_473_600..=1_833_029_933_770).contains(&ts));
521    }
522
523    #[test]
524    fn to_unix_time_millis() {
525        assert_eq!(
526            FileTime::NT_TIME_EPOCH.to_unix_time_millis(),
527            -11_644_473_600_000
528        );
529        assert_eq!(FileTime::new(1).to_unix_time_millis(), -11_644_473_600_000);
530        assert_eq!(
531            FileTime::new(9999).to_unix_time_millis(),
532            -11_644_473_600_000
533        );
534        assert_eq!(
535            FileTime::new(10000).to_unix_time_millis(),
536            -11_644_473_599_999
537        );
538        assert_eq!(
539            (FileTime::UNIX_EPOCH - Duration::from_millis(1)).to_unix_time_millis(),
540            i64::default() - 1
541        );
542        assert_eq!(
543            (FileTime::UNIX_EPOCH - Duration::from_nanos(999_900)).to_unix_time_millis(),
544            i64::default() - 1
545        );
546        assert_eq!(
547            (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time_millis(),
548            i64::default() - 1
549        );
550        assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_millis(), i64::default());
551        assert_eq!(
552            (FileTime::UNIX_EPOCH + Duration::from_nanos(999_900)).to_unix_time_millis(),
553            i64::default()
554        );
555        assert_eq!(
556            (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time_millis(),
557            i64::default()
558        );
559        assert_eq!(
560            (FileTime::UNIX_EPOCH + Duration::from_millis(1)).to_unix_time_millis(),
561            i64::default() + 1
562        );
563        assert_eq!(
564            FileTime::SIGNED_MAX.to_unix_time_millis(),
565            910_692_730_085_477
566        );
567        assert_eq!(
568            (FileTime::MAX - Duration::from_nanos(161_600)).to_unix_time_millis(),
569            1_833_029_933_770_954
570        );
571        assert_eq!(
572            (FileTime::MAX - Duration::from_nanos(161_500)).to_unix_time_millis(),
573            1_833_029_933_770_955
574        );
575        assert_eq!(
576            (FileTime::MAX - Duration::from_nanos(161_400)).to_unix_time_millis(),
577            1_833_029_933_770_955
578        );
579        assert_eq!(FileTime::MAX.to_unix_time_millis(), 1_833_029_933_770_955);
580    }
581
582    #[cfg(feature = "std")]
583    #[test_strategy::proptest]
584    fn to_unix_time_millis_roundtrip(ft: u64) {
585        use proptest::prop_assert;
586
587        let ts = FileTime::new(ft).to_unix_time_millis();
588        prop_assert!((-11_644_473_600_000..=1_833_029_933_770_955).contains(&ts));
589    }
590
591    #[test]
592    fn to_unix_time_micros() {
593        assert_eq!(
594            FileTime::NT_TIME_EPOCH.to_unix_time_micros(),
595            -11_644_473_600_000_000
596        );
597        assert_eq!(
598            FileTime::new(1).to_unix_time_micros(),
599            -11_644_473_600_000_000
600        );
601        assert_eq!(
602            FileTime::new(9).to_unix_time_micros(),
603            -11_644_473_600_000_000
604        );
605        assert_eq!(
606            FileTime::new(10).to_unix_time_micros(),
607            -11_644_473_599_999_999
608        );
609        assert_eq!(
610            (FileTime::UNIX_EPOCH - Duration::from_micros(1)).to_unix_time_micros(),
611            i64::default() - 1
612        );
613        assert_eq!(
614            (FileTime::UNIX_EPOCH - Duration::from_nanos(900)).to_unix_time_micros(),
615            i64::default() - 1
616        );
617        assert_eq!(
618            (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time_micros(),
619            i64::default() - 1
620        );
621        assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_micros(), i64::default());
622        assert_eq!(
623            (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time_micros(),
624            i64::default()
625        );
626        assert_eq!(
627            (FileTime::UNIX_EPOCH + Duration::from_nanos(900)).to_unix_time_micros(),
628            i64::default()
629        );
630        assert_eq!(
631            (FileTime::UNIX_EPOCH + Duration::from_micros(1)).to_unix_time_micros(),
632            i64::default() + 1
633        );
634        assert_eq!(
635            FileTime::SIGNED_MAX.to_unix_time_micros(),
636            910_692_730_085_477_580
637        );
638        assert_eq!(
639            (FileTime::MAX - Duration::from_nanos(600)).to_unix_time_micros(),
640            1_833_029_933_770_955_160
641        );
642        assert_eq!(
643            (FileTime::MAX - Duration::from_nanos(500)).to_unix_time_micros(),
644            1_833_029_933_770_955_161
645        );
646        assert_eq!(
647            (FileTime::MAX - Duration::from_nanos(400)).to_unix_time_micros(),
648            1_833_029_933_770_955_161
649        );
650        assert_eq!(
651            FileTime::MAX.to_unix_time_micros(),
652            1_833_029_933_770_955_161
653        );
654    }
655
656    #[cfg(feature = "std")]
657    #[test_strategy::proptest]
658    fn to_unix_time_micros_roundtrip(ft: u64) {
659        use proptest::prop_assert;
660
661        let ts = FileTime::new(ft).to_unix_time_micros();
662        prop_assert!((-11_644_473_600_000_000..=1_833_029_933_770_955_161).contains(&ts));
663    }
664
665    #[test]
666    fn to_unix_time_nanos() {
667        assert_eq!(
668            FileTime::NT_TIME_EPOCH.to_unix_time_nanos(),
669            -11_644_473_600_000_000_000
670        );
671        assert_eq!(
672            FileTime::new(1).to_unix_time_nanos(),
673            -11_644_473_599_999_999_900
674        );
675        assert_eq!(
676            FileTime::new(FILE_TIMES_PER_SEC - 1).to_unix_time_nanos(),
677            -11_644_473_599_000_000_100
678        );
679        assert_eq!(
680            FileTime::new(FILE_TIMES_PER_SEC).to_unix_time_nanos(),
681            -11_644_473_599_000_000_000
682        );
683        assert_eq!(
684            (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time_nanos(),
685            i128::default() - 100
686        );
687        assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_nanos(), i128::default());
688        assert_eq!(
689            (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time_nanos(),
690            i128::default() + 100
691        );
692        assert_eq!(
693            FileTime::SIGNED_MAX.to_unix_time_nanos(),
694            910_692_730_085_477_580_700
695        );
696        assert_eq!(
697            (FileTime::MAX - Duration::from_nanos(100)).to_unix_time_nanos(),
698            1_833_029_933_770_955_161_400
699        );
700        assert_eq!(
701            FileTime::MAX.to_unix_time_nanos(),
702            1_833_029_933_770_955_161_500
703        );
704    }
705
706    #[cfg(feature = "std")]
707    #[test_strategy::proptest]
708    fn to_unix_time_nanos_roundtrip(ft: u64) {
709        use proptest::prop_assert;
710
711        let ts = FileTime::new(ft).to_unix_time_nanos();
712        prop_assert!((-11_644_473_600_000_000_000..=1_833_029_933_770_955_161_500).contains(&ts));
713    }
714
715    #[test]
716    fn from_unix_time_before_nt_time_epoch() {
717        assert_eq!(
718            FileTime::from_unix_time(-11_644_473_601, u32::MAX).unwrap_err(),
719            FileTimeRangeErrorKind::Negative.into()
720        );
721        assert_eq!(
722            FileTime::from_unix_time(-11_644_473_601, NANOS_PER_SEC).unwrap_err(),
723            FileTimeRangeErrorKind::Negative.into()
724        );
725        assert_eq!(
726            FileTime::from_unix_time(-11_644_473_601, NANOS_PER_SEC - 1).unwrap_err(),
727            FileTimeRangeErrorKind::Negative.into()
728        );
729        assert_eq!(
730            FileTime::from_unix_time(-11_644_473_601, NANOS_PER_SEC - 99).unwrap_err(),
731            FileTimeRangeErrorKind::Negative.into()
732        );
733        assert_eq!(
734            FileTime::from_unix_time(-11_644_473_601, NANOS_PER_SEC - 100).unwrap_err(),
735            FileTimeRangeErrorKind::Negative.into()
736        );
737        assert_eq!(
738            FileTime::from_unix_time(-11_644_473_601, u32::MIN).unwrap_err(),
739            FileTimeRangeErrorKind::Negative.into()
740        );
741        assert_eq!(
742            FileTime::from_unix_time(i64::MIN, u32::MAX).unwrap_err(),
743            FileTimeRangeErrorKind::Negative.into()
744        );
745        assert_eq!(
746            FileTime::from_unix_time(i64::MIN, NANOS_PER_SEC).unwrap_err(),
747            FileTimeRangeErrorKind::Negative.into()
748        );
749        assert_eq!(
750            FileTime::from_unix_time(i64::MIN, NANOS_PER_SEC - 1).unwrap_err(),
751            FileTimeRangeErrorKind::Negative.into()
752        );
753        assert_eq!(
754            FileTime::from_unix_time(i64::MIN, u32::MIN).unwrap_err(),
755            FileTimeRangeErrorKind::Negative.into()
756        );
757    }
758
759    #[cfg(feature = "std")]
760    #[test_strategy::proptest]
761    fn from_unix_time_before_nt_time_epoch_roundtrip(
762        #[strategy(..=-11_644_473_601_i64)] secs: i64,
763        nanos: u32,
764    ) {
765        use proptest::prop_assert_eq;
766
767        prop_assert_eq!(
768            FileTime::from_unix_time(secs, nanos).unwrap_err(),
769            FileTimeRangeErrorKind::Negative.into()
770        );
771    }
772
773    #[test]
774    fn from_unix_time() {
775        assert_eq!(
776            FileTime::from_unix_time(-11_644_473_600, 0).unwrap(),
777            FileTime::NT_TIME_EPOCH
778        );
779        assert_eq!(
780            FileTime::from_unix_time(-11_644_473_600, 1).unwrap(),
781            FileTime::NT_TIME_EPOCH
782        );
783        assert_eq!(
784            FileTime::from_unix_time(-11_644_473_600, 99).unwrap(),
785            FileTime::NT_TIME_EPOCH
786        );
787        assert_eq!(
788            FileTime::from_unix_time(-11_644_473_600, 100).unwrap(),
789            FileTime::new(1)
790        );
791        assert_eq!(
792            FileTime::from_unix_time(-11_644_473_600, NANOS_PER_SEC - 100).unwrap(),
793            FileTime::new(FILE_TIMES_PER_SEC - 1)
794        );
795        assert_eq!(
796            FileTime::from_unix_time(-11_644_473_600, NANOS_PER_SEC - 99).unwrap(),
797            FileTime::new(FILE_TIMES_PER_SEC - 1)
798        );
799        assert_eq!(
800            FileTime::from_unix_time(-11_644_473_600, NANOS_PER_SEC - 1).unwrap(),
801            FileTime::new(FILE_TIMES_PER_SEC - 1)
802        );
803        assert_eq!(
804            FileTime::from_unix_time(-11_644_473_600, NANOS_PER_SEC).unwrap(),
805            FileTime::new(FILE_TIMES_PER_SEC)
806        );
807        assert_eq!(
808            FileTime::from_unix_time(-11_644_473_599, 0).unwrap(),
809            FileTime::new(FILE_TIMES_PER_SEC)
810        );
811        assert_eq!(
812            FileTime::from_unix_time(i64::default() - 1, NANOS_PER_SEC - 100).unwrap(),
813            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
814        );
815        assert_eq!(
816            FileTime::from_unix_time(i64::default() - 1, NANOS_PER_SEC - 99).unwrap(),
817            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
818        );
819        assert_eq!(
820            FileTime::from_unix_time(i64::default() - 1, NANOS_PER_SEC - 1).unwrap(),
821            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
822        );
823        assert_eq!(
824            FileTime::from_unix_time(i64::default() - 1, NANOS_PER_SEC).unwrap(),
825            FileTime::UNIX_EPOCH
826        );
827        assert_eq!(
828            FileTime::from_unix_time(i64::default(), u32::MIN).unwrap(),
829            FileTime::UNIX_EPOCH
830        );
831        assert_eq!(
832            FileTime::from_unix_time(i64::default(), 1).unwrap(),
833            FileTime::UNIX_EPOCH
834        );
835        assert_eq!(
836            FileTime::from_unix_time(i64::default(), 99).unwrap(),
837            FileTime::UNIX_EPOCH
838        );
839        assert_eq!(
840            FileTime::from_unix_time(i64::default(), 100).unwrap(),
841            FileTime::UNIX_EPOCH + Duration::from_nanos(100)
842        );
843        assert_eq!(
844            FileTime::from_unix_time(910_692_730_085, 477_580_700).unwrap(),
845            FileTime::SIGNED_MAX
846        );
847        assert_eq!(
848            FileTime::from_unix_time(1_833_029_933_770, 955_161_500).unwrap(),
849            FileTime::MAX
850        );
851        assert_eq!(
852            FileTime::from_unix_time(1_833_029_933_770, 955_161_501).unwrap(),
853            FileTime::MAX
854        );
855        assert_eq!(
856            FileTime::from_unix_time(1_833_029_933_770, 955_161_599).unwrap(),
857            FileTime::MAX
858        );
859    }
860
861    #[cfg(feature = "std")]
862    #[test_strategy::proptest]
863    fn from_unix_time_roundtrip(
864        #[strategy(-11_644_473_600..=1_833_029_933_770_i64)] secs: i64,
865        #[strategy(..NANOS_PER_SEC)] nanos: u32,
866    ) {
867        use proptest::{prop_assert, prop_assume};
868
869        if secs == 1_833_029_933_770 {
870            prop_assume!(nanos < 955_161_600);
871        }
872
873        prop_assert!(FileTime::from_unix_time(secs, nanos).is_ok());
874    }
875
876    #[test]
877    fn from_unix_time_with_too_big_date_time() {
878        assert_eq!(
879            FileTime::from_unix_time(1_833_029_933_770, 955_161_600).unwrap_err(),
880            FileTimeRangeErrorKind::Overflow.into()
881        );
882        assert_eq!(
883            FileTime::from_unix_time(1_833_029_933_770, NANOS_PER_SEC - 1).unwrap_err(),
884            FileTimeRangeErrorKind::Overflow.into()
885        );
886        assert_eq!(
887            FileTime::from_unix_time(1_833_029_933_770, NANOS_PER_SEC).unwrap_err(),
888            FileTimeRangeErrorKind::Overflow.into()
889        );
890        assert_eq!(
891            FileTime::from_unix_time(1_833_029_933_770, u32::MAX).unwrap_err(),
892            FileTimeRangeErrorKind::Overflow.into()
893        );
894        assert_eq!(
895            FileTime::from_unix_time(i64::MAX, u32::MIN).unwrap_err(),
896            FileTimeRangeErrorKind::Overflow.into()
897        );
898        assert_eq!(
899            FileTime::from_unix_time(i64::MAX, NANOS_PER_SEC - 1).unwrap_err(),
900            FileTimeRangeErrorKind::Overflow.into()
901        );
902        assert_eq!(
903            FileTime::from_unix_time(i64::MAX, NANOS_PER_SEC).unwrap_err(),
904            FileTimeRangeErrorKind::Overflow.into()
905        );
906        assert_eq!(
907            FileTime::from_unix_time(i64::MAX, u32::MAX).unwrap_err(),
908            FileTimeRangeErrorKind::Overflow.into()
909        );
910    }
911
912    #[cfg(feature = "std")]
913    #[test_strategy::proptest]
914    fn from_unix_time_with_too_big_date_time_roundtrip(
915        #[strategy(1_833_029_933_770_i64..)] secs: i64,
916        #[strategy(..NANOS_PER_SEC)] nanos: u32,
917    ) {
918        use proptest::{prop_assert_eq, prop_assume};
919
920        if secs == 1_833_029_933_770 {
921            prop_assume!(nanos >= 955_161_600);
922        }
923
924        prop_assert_eq!(
925            FileTime::from_unix_time(secs, nanos).unwrap_err(),
926            FileTimeRangeErrorKind::Overflow.into()
927        );
928    }
929
930    #[test]
931    fn from_unix_time_secs_before_nt_time_epoch() {
932        assert_eq!(
933            FileTime::from_unix_time_secs(-11_644_473_601).unwrap_err(),
934            FileTimeRangeErrorKind::Negative.into()
935        );
936        assert_eq!(
937            FileTime::from_unix_time_secs(i64::MIN).unwrap_err(),
938            FileTimeRangeErrorKind::Negative.into()
939        );
940    }
941
942    #[cfg(feature = "std")]
943    #[test_strategy::proptest]
944    fn from_unix_time_secs_before_nt_time_epoch_roundtrip(
945        #[strategy(..=-11_644_473_601_i64)] ts: i64,
946    ) {
947        use proptest::prop_assert_eq;
948
949        prop_assert_eq!(
950            FileTime::from_unix_time_secs(ts).unwrap_err(),
951            FileTimeRangeErrorKind::Negative.into()
952        );
953    }
954
955    #[test]
956    fn from_unix_time_secs() {
957        assert_eq!(
958            FileTime::from_unix_time_secs(-11_644_473_600).unwrap(),
959            FileTime::NT_TIME_EPOCH
960        );
961        assert_eq!(
962            FileTime::from_unix_time_secs(-11_644_473_599).unwrap(),
963            FileTime::new(FILE_TIMES_PER_SEC)
964        );
965        assert_eq!(
966            FileTime::from_unix_time_secs(i64::default() - 1).unwrap(),
967            FileTime::UNIX_EPOCH - Duration::from_secs(1)
968        );
969        assert_eq!(
970            FileTime::from_unix_time_secs(i64::default()).unwrap(),
971            FileTime::UNIX_EPOCH
972        );
973        assert_eq!(
974            FileTime::from_unix_time_secs(i64::default() + 1).unwrap(),
975            FileTime::UNIX_EPOCH + Duration::from_secs(1)
976        );
977        assert_eq!(
978            FileTime::from_unix_time_secs(910_692_730_085).unwrap(),
979            FileTime::SIGNED_MAX - Duration::from_nanos(477_580_700)
980        );
981        assert_eq!(
982            FileTime::from_unix_time_secs(1_833_029_933_770).unwrap(),
983            FileTime::MAX - Duration::from_nanos(955_161_500)
984        );
985    }
986
987    #[cfg(feature = "std")]
988    #[test_strategy::proptest]
989    fn from_unix_time_secs_roundtrip(#[strategy(-11_644_473_600..=1_833_029_933_770_i64)] ts: i64) {
990        use proptest::prop_assert;
991
992        prop_assert!(FileTime::from_unix_time_secs(ts).is_ok());
993    }
994
995    #[test]
996    fn from_unix_time_secs_with_too_big_date_time() {
997        assert_eq!(
998            FileTime::from_unix_time_secs(1_833_029_933_771).unwrap_err(),
999            FileTimeRangeErrorKind::Overflow.into()
1000        );
1001        assert_eq!(
1002            FileTime::from_unix_time_secs(i64::MAX).unwrap_err(),
1003            FileTimeRangeErrorKind::Overflow.into()
1004        );
1005    }
1006
1007    #[cfg(feature = "std")]
1008    #[test_strategy::proptest]
1009    fn from_unix_time_secs_with_too_big_date_time_roundtrip(
1010        #[strategy(1_833_029_933_771_i64..)] ts: i64,
1011    ) {
1012        use proptest::prop_assert_eq;
1013
1014        prop_assert_eq!(
1015            FileTime::from_unix_time_secs(ts).unwrap_err(),
1016            FileTimeRangeErrorKind::Overflow.into()
1017        );
1018    }
1019
1020    #[test]
1021    fn from_unix_time_millis_before_nt_time_epoch() {
1022        assert_eq!(
1023            FileTime::from_unix_time_millis(-11_644_473_600_001).unwrap_err(),
1024            FileTimeRangeErrorKind::Negative.into()
1025        );
1026        assert_eq!(
1027            FileTime::from_unix_time_millis(i64::MIN).unwrap_err(),
1028            FileTimeRangeErrorKind::Negative.into()
1029        );
1030    }
1031
1032    #[cfg(feature = "std")]
1033    #[test_strategy::proptest]
1034    fn from_unix_time_millis_before_nt_time_epoch_roundtrip(
1035        #[strategy(..=-11_644_473_600_001_i64)] ts: i64,
1036    ) {
1037        use proptest::prop_assert_eq;
1038
1039        prop_assert_eq!(
1040            FileTime::from_unix_time_millis(ts).unwrap_err(),
1041            FileTimeRangeErrorKind::Negative.into()
1042        );
1043    }
1044
1045    #[test]
1046    fn from_unix_time_millis() {
1047        assert_eq!(
1048            FileTime::from_unix_time_millis(-11_644_473_600_000).unwrap(),
1049            FileTime::NT_TIME_EPOCH
1050        );
1051        assert_eq!(
1052            FileTime::from_unix_time_millis(-11_644_473_599_999).unwrap(),
1053            FileTime::new(10000)
1054        );
1055        assert_eq!(
1056            FileTime::from_unix_time_millis(i64::default() - 1).unwrap(),
1057            FileTime::UNIX_EPOCH - Duration::from_millis(1)
1058        );
1059        assert_eq!(
1060            FileTime::from_unix_time_millis(i64::default()).unwrap(),
1061            FileTime::UNIX_EPOCH
1062        );
1063        assert_eq!(
1064            FileTime::from_unix_time_millis(i64::default() + 1).unwrap(),
1065            FileTime::UNIX_EPOCH + Duration::from_millis(1)
1066        );
1067        assert_eq!(
1068            FileTime::from_unix_time_millis(910_692_730_085_477).unwrap(),
1069            FileTime::SIGNED_MAX - Duration::from_nanos(580_700)
1070        );
1071        assert_eq!(
1072            FileTime::from_unix_time_millis(1_833_029_933_770_955).unwrap(),
1073            FileTime::MAX - Duration::from_nanos(161_500)
1074        );
1075    }
1076
1077    #[cfg(feature = "std")]
1078    #[test_strategy::proptest]
1079    fn from_unix_time_millis_roundtrip(
1080        #[strategy(-11_644_473_600_000..=1_833_029_933_770_955_i64)] ts: i64,
1081    ) {
1082        use proptest::prop_assert;
1083
1084        prop_assert!(FileTime::from_unix_time_millis(ts).is_ok());
1085    }
1086
1087    #[test]
1088    fn from_unix_time_millis_with_too_big_date_time() {
1089        assert_eq!(
1090            FileTime::from_unix_time_millis(1_833_029_933_770_956).unwrap_err(),
1091            FileTimeRangeErrorKind::Overflow.into()
1092        );
1093        assert_eq!(
1094            FileTime::from_unix_time_millis(i64::MAX).unwrap_err(),
1095            FileTimeRangeErrorKind::Overflow.into()
1096        );
1097    }
1098
1099    #[cfg(feature = "std")]
1100    #[test_strategy::proptest]
1101    fn from_unix_time_millis_with_too_big_date_time_roundtrip(
1102        #[strategy(1_833_029_933_770_956_i64..)] ts: i64,
1103    ) {
1104        use proptest::prop_assert_eq;
1105
1106        prop_assert_eq!(
1107            FileTime::from_unix_time_millis(ts).unwrap_err(),
1108            FileTimeRangeErrorKind::Overflow.into()
1109        );
1110    }
1111
1112    #[test]
1113    fn from_unix_time_micros_before_nt_time_epoch() {
1114        assert_eq!(
1115            FileTime::from_unix_time_micros(-11_644_473_600_000_001).unwrap_err(),
1116            FileTimeRangeErrorKind::Negative.into()
1117        );
1118        assert_eq!(
1119            FileTime::from_unix_time_micros(i64::MIN).unwrap_err(),
1120            FileTimeRangeErrorKind::Negative.into()
1121        );
1122    }
1123
1124    #[cfg(feature = "std")]
1125    #[test_strategy::proptest]
1126    fn from_unix_time_micros_before_nt_time_epoch_roundtrip(
1127        #[strategy(..=-11_644_473_600_000_001_i64)] ts: i64,
1128    ) {
1129        use proptest::prop_assert_eq;
1130
1131        prop_assert_eq!(
1132            FileTime::from_unix_time_micros(ts).unwrap_err(),
1133            FileTimeRangeErrorKind::Negative.into()
1134        );
1135    }
1136
1137    #[test]
1138    fn from_unix_time_micros() {
1139        assert_eq!(
1140            FileTime::from_unix_time_micros(-11_644_473_600_000_000).unwrap(),
1141            FileTime::NT_TIME_EPOCH
1142        );
1143        assert_eq!(
1144            FileTime::from_unix_time_micros(-11_644_473_599_999_999).unwrap(),
1145            FileTime::new(10)
1146        );
1147        assert_eq!(
1148            FileTime::from_unix_time_micros(i64::default() - 1).unwrap(),
1149            FileTime::UNIX_EPOCH - Duration::from_micros(1)
1150        );
1151        assert_eq!(
1152            FileTime::from_unix_time_micros(i64::default()).unwrap(),
1153            FileTime::UNIX_EPOCH
1154        );
1155        assert_eq!(
1156            FileTime::from_unix_time_micros(i64::default() + 1).unwrap(),
1157            FileTime::UNIX_EPOCH + Duration::from_micros(1)
1158        );
1159        assert_eq!(
1160            FileTime::from_unix_time_micros(910_692_730_085_477_580).unwrap(),
1161            FileTime::SIGNED_MAX - Duration::from_nanos(700)
1162        );
1163        assert_eq!(
1164            FileTime::from_unix_time_micros(1_833_029_933_770_955_161).unwrap(),
1165            FileTime::MAX - Duration::from_nanos(500)
1166        );
1167    }
1168
1169    #[cfg(feature = "std")]
1170    #[test_strategy::proptest]
1171    fn from_unix_time_micros_roundtrip(
1172        #[strategy(-11_644_473_600_000_000..=1_833_029_933_770_955_161_i64)] ts: i64,
1173    ) {
1174        use proptest::prop_assert;
1175
1176        prop_assert!(FileTime::from_unix_time_micros(ts).is_ok());
1177    }
1178
1179    #[test]
1180    fn from_unix_time_micros_with_too_big_date_time() {
1181        assert_eq!(
1182            FileTime::from_unix_time_micros(1_833_029_933_770_955_162).unwrap_err(),
1183            FileTimeRangeErrorKind::Overflow.into()
1184        );
1185        assert_eq!(
1186            FileTime::from_unix_time_micros(i64::MAX).unwrap_err(),
1187            FileTimeRangeErrorKind::Overflow.into()
1188        );
1189    }
1190
1191    #[cfg(feature = "std")]
1192    #[test_strategy::proptest]
1193    fn from_unix_time_micros_with_too_big_date_time_roundtrip(
1194        #[strategy(1_833_029_933_770_955_162_i64..)] ts: i64,
1195    ) {
1196        use proptest::prop_assert_eq;
1197
1198        prop_assert_eq!(
1199            FileTime::from_unix_time_micros(ts).unwrap_err(),
1200            FileTimeRangeErrorKind::Overflow.into()
1201        );
1202    }
1203
1204    #[test]
1205    fn from_unix_time_nanos_before_nt_time_epoch() {
1206        assert_eq!(
1207            FileTime::from_unix_time_nanos(-11_644_473_600_000_000_100).unwrap_err(),
1208            FileTimeRangeErrorKind::Negative.into()
1209        );
1210        assert_eq!(
1211            FileTime::from_unix_time_nanos(-11_644_473_600_000_000_099).unwrap_err(),
1212            FileTimeRangeErrorKind::Negative.into()
1213        );
1214        assert_eq!(
1215            FileTime::from_unix_time_nanos(-11_644_473_600_000_000_001).unwrap_err(),
1216            FileTimeRangeErrorKind::Negative.into()
1217        );
1218        assert_eq!(
1219            FileTime::from_unix_time_nanos(i128::MIN).unwrap_err(),
1220            FileTimeRangeErrorKind::Negative.into()
1221        );
1222    }
1223
1224    #[cfg(feature = "std")]
1225    #[test_strategy::proptest]
1226    fn from_unix_time_nanos_before_nt_time_epoch_roundtrip(
1227        #[strategy(..=-11_644_473_600_000_000_001_i128)] ts: i128,
1228    ) {
1229        use proptest::prop_assert_eq;
1230
1231        prop_assert_eq!(
1232            FileTime::from_unix_time_nanos(ts).unwrap_err(),
1233            FileTimeRangeErrorKind::Negative.into()
1234        );
1235    }
1236
1237    #[test]
1238    fn from_unix_time_nanos() {
1239        assert_eq!(
1240            FileTime::from_unix_time_nanos(-11_644_473_600_000_000_000).unwrap(),
1241            FileTime::NT_TIME_EPOCH
1242        );
1243        assert_eq!(
1244            FileTime::from_unix_time_nanos(-11_644_473_599_999_999_999).unwrap(),
1245            FileTime::NT_TIME_EPOCH
1246        );
1247        assert_eq!(
1248            FileTime::from_unix_time_nanos(-11_644_473_599_999_999_901).unwrap(),
1249            FileTime::NT_TIME_EPOCH
1250        );
1251        assert_eq!(
1252            FileTime::from_unix_time_nanos(-11_644_473_599_999_999_900).unwrap(),
1253            FileTime::new(1)
1254        );
1255        assert_eq!(
1256            FileTime::from_unix_time_nanos(-11_644_473_599_000_000_100).unwrap(),
1257            FileTime::new(FILE_TIMES_PER_SEC - 1)
1258        );
1259        assert_eq!(
1260            FileTime::from_unix_time_nanos(-11_644_473_599_000_000_099).unwrap(),
1261            FileTime::new(FILE_TIMES_PER_SEC - 1)
1262        );
1263        assert_eq!(
1264            FileTime::from_unix_time_nanos(-11_644_473_599_000_000_001).unwrap(),
1265            FileTime::new(FILE_TIMES_PER_SEC - 1)
1266        );
1267        assert_eq!(
1268            FileTime::from_unix_time_nanos(-11_644_473_599_000_000_000).unwrap(),
1269            FileTime::new(FILE_TIMES_PER_SEC)
1270        );
1271        assert_eq!(
1272            FileTime::from_unix_time_nanos(i128::default() - 100).unwrap(),
1273            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
1274        );
1275        assert_eq!(
1276            FileTime::from_unix_time_nanos(i128::default() - 99).unwrap(),
1277            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
1278        );
1279        assert_eq!(
1280            FileTime::from_unix_time_nanos(i128::default() - 1).unwrap(),
1281            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
1282        );
1283        assert_eq!(
1284            FileTime::from_unix_time_nanos(i128::default()).unwrap(),
1285            FileTime::UNIX_EPOCH
1286        );
1287        assert_eq!(
1288            FileTime::from_unix_time_nanos(i128::default() + 1).unwrap(),
1289            FileTime::UNIX_EPOCH
1290        );
1291        assert_eq!(
1292            FileTime::from_unix_time_nanos(i128::default() + 99).unwrap(),
1293            FileTime::UNIX_EPOCH
1294        );
1295        assert_eq!(
1296            FileTime::from_unix_time_nanos(i128::default() + 100).unwrap(),
1297            FileTime::UNIX_EPOCH + Duration::from_nanos(100)
1298        );
1299        assert_eq!(
1300            FileTime::from_unix_time_nanos(910_692_730_085_477_580_700).unwrap(),
1301            FileTime::SIGNED_MAX
1302        );
1303        assert_eq!(
1304            FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_500).unwrap(),
1305            FileTime::MAX
1306        );
1307    }
1308
1309    #[cfg(feature = "std")]
1310    #[test_strategy::proptest]
1311    fn from_unix_time_nanos_roundtrip(
1312        #[strategy(-11_644_473_600_000_000_000..=1_833_029_933_770_955_161_500_i128)] ts: i128,
1313    ) {
1314        use proptest::prop_assert;
1315
1316        prop_assert!(FileTime::from_unix_time_nanos(ts).is_ok());
1317    }
1318
1319    #[test]
1320    fn from_unix_time_nanos_with_too_big_date_time() {
1321        assert_eq!(
1322            FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_501).unwrap_err(),
1323            FileTimeRangeErrorKind::Overflow.into()
1324        );
1325        assert_eq!(
1326            FileTime::from_unix_time_nanos(i128::MAX).unwrap_err(),
1327            FileTimeRangeErrorKind::Overflow.into()
1328        );
1329    }
1330
1331    #[cfg(feature = "std")]
1332    #[test_strategy::proptest]
1333    fn from_unix_time_nanos_with_too_big_date_time_roundtrip(
1334        #[strategy(1_833_029_933_770_955_161_501_i128..)] ts: i128,
1335    ) {
1336        use proptest::prop_assert_eq;
1337
1338        prop_assert_eq!(
1339            FileTime::from_unix_time_nanos(ts).unwrap_err(),
1340            FileTimeRangeErrorKind::Overflow.into()
1341        );
1342    }
1343}