Skip to main content

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