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