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        let ft = Self::from_unix_time_secs(secs)?;
221        ft.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            let ft = Self::new(duration * FILE_TIMES_PER_SEC);
264            Ok(ft)
265        } else {
266            Err(FileTimeRangeErrorKind::Overflow.into())
267        }
268    }
269
270    /// Creates a `FileTime` with the given [Unix time] in milliseconds.
271    ///
272    /// # Errors
273    ///
274    /// Returns [`Err`] if `millis` is out of range for the file time.
275    ///
276    /// # Examples
277    ///
278    /// ```
279    /// # use core::time::Duration;
280    /// #
281    /// # use nt_time::FileTime;
282    /// #
283    /// assert_eq!(
284    ///     FileTime::from_unix_time_millis(-11_644_473_600_000),
285    ///     Ok(FileTime::NT_TIME_EPOCH)
286    /// );
287    /// assert_eq!(FileTime::from_unix_time_millis(0), Ok(FileTime::UNIX_EPOCH));
288    /// assert_eq!(
289    ///     FileTime::from_unix_time_millis(910_692_730_085_477),
290    ///     Ok(FileTime::SIGNED_MAX - Duration::from_nanos(580_700))
291    /// );
292    /// assert_eq!(
293    ///     FileTime::from_unix_time_millis(1_833_029_933_770_955),
294    ///     Ok(FileTime::MAX - Duration::from_nanos(161_500))
295    /// );
296    ///
297    /// // Before `1601-01-01 00:00:00 UTC`.
298    /// assert!(FileTime::from_unix_time_millis(-11_644_473_600_001).is_err());
299    /// // After `+60056-05-28 05:36:10.955161500 UTC`.
300    /// assert!(FileTime::from_unix_time_millis(1_833_029_933_770_956).is_err());
301    /// ```
302    ///
303    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
304    pub fn from_unix_time_millis(millis: i64) -> Result<Self, FileTimeRangeError> {
305        let nanos = i128::from(millis) * 1_000_000;
306        Self::from_unix_time_nanos(nanos)
307    }
308
309    /// Creates a `FileTime` with the given [Unix time] in microseconds.
310    ///
311    /// # Errors
312    ///
313    /// Returns [`Err`] if `micros` is out of range for the file time.
314    ///
315    /// # Examples
316    ///
317    /// ```
318    /// # use core::time::Duration;
319    /// #
320    /// # use nt_time::FileTime;
321    /// #
322    /// assert_eq!(
323    ///     FileTime::from_unix_time_micros(-11_644_473_600_000_000),
324    ///     Ok(FileTime::NT_TIME_EPOCH)
325    /// );
326    /// assert_eq!(FileTime::from_unix_time_micros(0), Ok(FileTime::UNIX_EPOCH));
327    /// assert_eq!(
328    ///     FileTime::from_unix_time_micros(910_692_730_085_477_580),
329    ///     Ok(FileTime::SIGNED_MAX - Duration::from_nanos(700))
330    /// );
331    /// assert_eq!(
332    ///     FileTime::from_unix_time_micros(1_833_029_933_770_955_161),
333    ///     Ok(FileTime::MAX - Duration::from_nanos(500))
334    /// );
335    ///
336    /// // Before `1601-01-01 00:00:00 UTC`.
337    /// assert!(FileTime::from_unix_time_micros(-11_644_473_600_000_001).is_err());
338    /// // After `+60056-05-28 05:36:10.955161500 UTC`.
339    /// assert!(FileTime::from_unix_time_micros(1_833_029_933_770_955_162).is_err());
340    /// ```
341    ///
342    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
343    pub fn from_unix_time_micros(micros: i64) -> Result<Self, FileTimeRangeError> {
344        let nanos = i128::from(micros) * 1000;
345        Self::from_unix_time_nanos(nanos)
346    }
347
348    /// Creates a `FileTime` with the given [Unix time] in nanoseconds.
349    ///
350    /// # Errors
351    ///
352    /// Returns [`Err`] if `nanos` is out of range for the file time.
353    ///
354    /// # Examples
355    ///
356    /// ```
357    /// # use nt_time::FileTime;
358    /// #
359    /// assert_eq!(
360    ///     FileTime::from_unix_time_nanos(-11_644_473_600_000_000_000),
361    ///     Ok(FileTime::NT_TIME_EPOCH)
362    /// );
363    /// assert_eq!(FileTime::from_unix_time_nanos(0), Ok(FileTime::UNIX_EPOCH));
364    /// assert_eq!(
365    ///     FileTime::from_unix_time_nanos(910_692_730_085_477_580_700),
366    ///     Ok(FileTime::SIGNED_MAX)
367    /// );
368    /// assert_eq!(
369    ///     FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_500),
370    ///     Ok(FileTime::MAX)
371    /// );
372    ///
373    /// // Before `1601-01-01 00:00:00 UTC`.
374    /// assert!(FileTime::from_unix_time_nanos(-11_644_473_600_000_000_001).is_err());
375    /// // After `+60056-05-28 05:36:10.955161500 UTC`.
376    /// assert!(FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_501).is_err());
377    /// ```
378    ///
379    /// [Unix time]: https://en.wikipedia.org/wiki/Unix_time
380    pub fn from_unix_time_nanos(nanos: i128) -> Result<Self, FileTimeRangeError> {
381        if nanos <= 1_833_029_933_770_955_161_500 {
382            let ft = (nanos + 11_644_473_600_000_000_000)
383                .div_euclid(100)
384                .try_into()
385                .map_err(|_| FileTimeRangeErrorKind::Negative)?;
386            let ft = Self::new(ft);
387            Ok(ft)
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, prop_assume};
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: FileTime) {
449        let ts = 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: FileTime) {
510        let ts = 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: FileTime) {
576        let ts = 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: FileTime) {
648        let ts = 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: FileTime) {
696        let ts = 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        if secs == 1_833_029_933_770 {
851            prop_assume!(nanos < 955_161_600);
852        }
853
854        prop_assert!(FileTime::from_unix_time(secs, nanos).is_ok());
855    }
856
857    #[test]
858    fn from_unix_time_with_too_big_date_time() {
859        assert_eq!(
860            FileTime::from_unix_time(1_833_029_933_770, 955_161_600).unwrap_err(),
861            FileTimeRangeErrorKind::Overflow.into()
862        );
863        assert_eq!(
864            FileTime::from_unix_time(1_833_029_933_770, NANOS_PER_SEC - 1).unwrap_err(),
865            FileTimeRangeErrorKind::Overflow.into()
866        );
867        assert_eq!(
868            FileTime::from_unix_time(1_833_029_933_770, NANOS_PER_SEC).unwrap_err(),
869            FileTimeRangeErrorKind::Overflow.into()
870        );
871        assert_eq!(
872            FileTime::from_unix_time(1_833_029_933_770, u32::MAX).unwrap_err(),
873            FileTimeRangeErrorKind::Overflow.into()
874        );
875        assert_eq!(
876            FileTime::from_unix_time(i64::MAX, u32::MIN).unwrap_err(),
877            FileTimeRangeErrorKind::Overflow.into()
878        );
879        assert_eq!(
880            FileTime::from_unix_time(i64::MAX, NANOS_PER_SEC - 1).unwrap_err(),
881            FileTimeRangeErrorKind::Overflow.into()
882        );
883        assert_eq!(
884            FileTime::from_unix_time(i64::MAX, NANOS_PER_SEC).unwrap_err(),
885            FileTimeRangeErrorKind::Overflow.into()
886        );
887        assert_eq!(
888            FileTime::from_unix_time(i64::MAX, u32::MAX).unwrap_err(),
889            FileTimeRangeErrorKind::Overflow.into()
890        );
891    }
892
893    #[cfg(feature = "std")]
894    #[proptest]
895    fn from_unix_time_with_too_big_date_time_roundtrip(
896        #[strategy(1_833_029_933_770_i64..)] secs: i64,
897        #[strategy(..NANOS_PER_SEC)] nanos: u32,
898    ) {
899        if secs == 1_833_029_933_770 {
900            prop_assume!(nanos >= 955_161_600);
901        }
902
903        prop_assert_eq!(
904            FileTime::from_unix_time(secs, nanos).unwrap_err(),
905            FileTimeRangeErrorKind::Overflow.into()
906        );
907    }
908
909    #[test]
910    fn from_unix_time_secs_before_nt_time_epoch() {
911        assert_eq!(
912            FileTime::from_unix_time_secs(-11_644_473_601).unwrap_err(),
913            FileTimeRangeErrorKind::Negative.into()
914        );
915        assert_eq!(
916            FileTime::from_unix_time_secs(i64::MIN).unwrap_err(),
917            FileTimeRangeErrorKind::Negative.into()
918        );
919    }
920
921    #[cfg(feature = "std")]
922    #[proptest]
923    fn from_unix_time_secs_before_nt_time_epoch_roundtrip(
924        #[strategy(..=-11_644_473_601_i64)] ts: i64,
925    ) {
926        prop_assert_eq!(
927            FileTime::from_unix_time_secs(ts).unwrap_err(),
928            FileTimeRangeErrorKind::Negative.into()
929        );
930    }
931
932    #[test]
933    fn from_unix_time_secs() {
934        assert_eq!(
935            FileTime::from_unix_time_secs(-11_644_473_600).unwrap(),
936            FileTime::NT_TIME_EPOCH
937        );
938        assert_eq!(
939            FileTime::from_unix_time_secs(-11_644_473_599).unwrap(),
940            FileTime::new(FILE_TIMES_PER_SEC)
941        );
942        assert_eq!(
943            FileTime::from_unix_time_secs(i64::default() - 1).unwrap(),
944            FileTime::UNIX_EPOCH - Duration::from_secs(1)
945        );
946        assert_eq!(
947            FileTime::from_unix_time_secs(i64::default()).unwrap(),
948            FileTime::UNIX_EPOCH
949        );
950        assert_eq!(
951            FileTime::from_unix_time_secs(i64::default() + 1).unwrap(),
952            FileTime::UNIX_EPOCH + Duration::from_secs(1)
953        );
954        assert_eq!(
955            FileTime::from_unix_time_secs(910_692_730_085).unwrap(),
956            FileTime::SIGNED_MAX - Duration::from_nanos(477_580_700)
957        );
958        assert_eq!(
959            FileTime::from_unix_time_secs(1_833_029_933_770).unwrap(),
960            FileTime::MAX - Duration::from_nanos(955_161_500)
961        );
962    }
963
964    #[cfg(feature = "std")]
965    #[proptest]
966    fn from_unix_time_secs_roundtrip(#[strategy(-11_644_473_600..=1_833_029_933_770_i64)] ts: i64) {
967        prop_assert!(FileTime::from_unix_time_secs(ts).is_ok());
968    }
969
970    #[test]
971    fn from_unix_time_secs_with_too_big_date_time() {
972        assert_eq!(
973            FileTime::from_unix_time_secs(1_833_029_933_771).unwrap_err(),
974            FileTimeRangeErrorKind::Overflow.into()
975        );
976        assert_eq!(
977            FileTime::from_unix_time_secs(i64::MAX).unwrap_err(),
978            FileTimeRangeErrorKind::Overflow.into()
979        );
980    }
981
982    #[cfg(feature = "std")]
983    #[proptest]
984    fn from_unix_time_secs_with_too_big_date_time_roundtrip(
985        #[strategy(1_833_029_933_771_i64..)] ts: i64,
986    ) {
987        prop_assert_eq!(
988            FileTime::from_unix_time_secs(ts).unwrap_err(),
989            FileTimeRangeErrorKind::Overflow.into()
990        );
991    }
992
993    #[test]
994    fn from_unix_time_millis_before_nt_time_epoch() {
995        assert_eq!(
996            FileTime::from_unix_time_millis(-11_644_473_600_001).unwrap_err(),
997            FileTimeRangeErrorKind::Negative.into()
998        );
999        assert_eq!(
1000            FileTime::from_unix_time_millis(i64::MIN).unwrap_err(),
1001            FileTimeRangeErrorKind::Negative.into()
1002        );
1003    }
1004
1005    #[cfg(feature = "std")]
1006    #[proptest]
1007    fn from_unix_time_millis_before_nt_time_epoch_roundtrip(
1008        #[strategy(..=-11_644_473_600_001_i64)] ts: i64,
1009    ) {
1010        prop_assert_eq!(
1011            FileTime::from_unix_time_millis(ts).unwrap_err(),
1012            FileTimeRangeErrorKind::Negative.into()
1013        );
1014    }
1015
1016    #[test]
1017    fn from_unix_time_millis() {
1018        assert_eq!(
1019            FileTime::from_unix_time_millis(-11_644_473_600_000).unwrap(),
1020            FileTime::NT_TIME_EPOCH
1021        );
1022        assert_eq!(
1023            FileTime::from_unix_time_millis(-11_644_473_599_999).unwrap(),
1024            FileTime::new(10000)
1025        );
1026        assert_eq!(
1027            FileTime::from_unix_time_millis(i64::default() - 1).unwrap(),
1028            FileTime::UNIX_EPOCH - Duration::from_millis(1)
1029        );
1030        assert_eq!(
1031            FileTime::from_unix_time_millis(i64::default()).unwrap(),
1032            FileTime::UNIX_EPOCH
1033        );
1034        assert_eq!(
1035            FileTime::from_unix_time_millis(i64::default() + 1).unwrap(),
1036            FileTime::UNIX_EPOCH + Duration::from_millis(1)
1037        );
1038        assert_eq!(
1039            FileTime::from_unix_time_millis(910_692_730_085_477).unwrap(),
1040            FileTime::SIGNED_MAX - Duration::from_nanos(580_700)
1041        );
1042        assert_eq!(
1043            FileTime::from_unix_time_millis(1_833_029_933_770_955).unwrap(),
1044            FileTime::MAX - Duration::from_nanos(161_500)
1045        );
1046    }
1047
1048    #[cfg(feature = "std")]
1049    #[proptest]
1050    fn from_unix_time_millis_roundtrip(
1051        #[strategy(-11_644_473_600_000..=1_833_029_933_770_955_i64)] ts: i64,
1052    ) {
1053        prop_assert!(FileTime::from_unix_time_millis(ts).is_ok());
1054    }
1055
1056    #[test]
1057    fn from_unix_time_millis_with_too_big_date_time() {
1058        assert_eq!(
1059            FileTime::from_unix_time_millis(1_833_029_933_770_956).unwrap_err(),
1060            FileTimeRangeErrorKind::Overflow.into()
1061        );
1062        assert_eq!(
1063            FileTime::from_unix_time_millis(i64::MAX).unwrap_err(),
1064            FileTimeRangeErrorKind::Overflow.into()
1065        );
1066    }
1067
1068    #[cfg(feature = "std")]
1069    #[proptest]
1070    fn from_unix_time_millis_with_too_big_date_time_roundtrip(
1071        #[strategy(1_833_029_933_770_956_i64..)] ts: i64,
1072    ) {
1073        prop_assert_eq!(
1074            FileTime::from_unix_time_millis(ts).unwrap_err(),
1075            FileTimeRangeErrorKind::Overflow.into()
1076        );
1077    }
1078
1079    #[test]
1080    fn from_unix_time_micros_before_nt_time_epoch() {
1081        assert_eq!(
1082            FileTime::from_unix_time_micros(-11_644_473_600_000_001).unwrap_err(),
1083            FileTimeRangeErrorKind::Negative.into()
1084        );
1085        assert_eq!(
1086            FileTime::from_unix_time_micros(i64::MIN).unwrap_err(),
1087            FileTimeRangeErrorKind::Negative.into()
1088        );
1089    }
1090
1091    #[cfg(feature = "std")]
1092    #[proptest]
1093    fn from_unix_time_micros_before_nt_time_epoch_roundtrip(
1094        #[strategy(..=-11_644_473_600_000_001_i64)] ts: i64,
1095    ) {
1096        prop_assert_eq!(
1097            FileTime::from_unix_time_micros(ts).unwrap_err(),
1098            FileTimeRangeErrorKind::Negative.into()
1099        );
1100    }
1101
1102    #[test]
1103    fn from_unix_time_micros() {
1104        assert_eq!(
1105            FileTime::from_unix_time_micros(-11_644_473_600_000_000).unwrap(),
1106            FileTime::NT_TIME_EPOCH
1107        );
1108        assert_eq!(
1109            FileTime::from_unix_time_micros(-11_644_473_599_999_999).unwrap(),
1110            FileTime::new(10)
1111        );
1112        assert_eq!(
1113            FileTime::from_unix_time_micros(i64::default() - 1).unwrap(),
1114            FileTime::UNIX_EPOCH - Duration::from_micros(1)
1115        );
1116        assert_eq!(
1117            FileTime::from_unix_time_micros(i64::default()).unwrap(),
1118            FileTime::UNIX_EPOCH
1119        );
1120        assert_eq!(
1121            FileTime::from_unix_time_micros(i64::default() + 1).unwrap(),
1122            FileTime::UNIX_EPOCH + Duration::from_micros(1)
1123        );
1124        assert_eq!(
1125            FileTime::from_unix_time_micros(910_692_730_085_477_580).unwrap(),
1126            FileTime::SIGNED_MAX - Duration::from_nanos(700)
1127        );
1128        assert_eq!(
1129            FileTime::from_unix_time_micros(1_833_029_933_770_955_161).unwrap(),
1130            FileTime::MAX - Duration::from_nanos(500)
1131        );
1132    }
1133
1134    #[cfg(feature = "std")]
1135    #[proptest]
1136    fn from_unix_time_micros_roundtrip(
1137        #[strategy(-11_644_473_600_000_000..=1_833_029_933_770_955_161_i64)] ts: i64,
1138    ) {
1139        prop_assert!(FileTime::from_unix_time_micros(ts).is_ok());
1140    }
1141
1142    #[test]
1143    fn from_unix_time_micros_with_too_big_date_time() {
1144        assert_eq!(
1145            FileTime::from_unix_time_micros(1_833_029_933_770_955_162).unwrap_err(),
1146            FileTimeRangeErrorKind::Overflow.into()
1147        );
1148        assert_eq!(
1149            FileTime::from_unix_time_micros(i64::MAX).unwrap_err(),
1150            FileTimeRangeErrorKind::Overflow.into()
1151        );
1152    }
1153
1154    #[cfg(feature = "std")]
1155    #[proptest]
1156    fn from_unix_time_micros_with_too_big_date_time_roundtrip(
1157        #[strategy(1_833_029_933_770_955_162_i64..)] ts: i64,
1158    ) {
1159        prop_assert_eq!(
1160            FileTime::from_unix_time_micros(ts).unwrap_err(),
1161            FileTimeRangeErrorKind::Overflow.into()
1162        );
1163    }
1164
1165    #[test]
1166    fn from_unix_time_nanos_before_nt_time_epoch() {
1167        assert_eq!(
1168            FileTime::from_unix_time_nanos(-11_644_473_600_000_000_100).unwrap_err(),
1169            FileTimeRangeErrorKind::Negative.into()
1170        );
1171        assert_eq!(
1172            FileTime::from_unix_time_nanos(-11_644_473_600_000_000_099).unwrap_err(),
1173            FileTimeRangeErrorKind::Negative.into()
1174        );
1175        assert_eq!(
1176            FileTime::from_unix_time_nanos(-11_644_473_600_000_000_001).unwrap_err(),
1177            FileTimeRangeErrorKind::Negative.into()
1178        );
1179        assert_eq!(
1180            FileTime::from_unix_time_nanos(i128::MIN).unwrap_err(),
1181            FileTimeRangeErrorKind::Negative.into()
1182        );
1183    }
1184
1185    #[cfg(feature = "std")]
1186    #[proptest]
1187    fn from_unix_time_nanos_before_nt_time_epoch_roundtrip(
1188        #[strategy(..=-11_644_473_600_000_000_001_i128)] ts: i128,
1189    ) {
1190        prop_assert_eq!(
1191            FileTime::from_unix_time_nanos(ts).unwrap_err(),
1192            FileTimeRangeErrorKind::Negative.into()
1193        );
1194    }
1195
1196    #[test]
1197    fn from_unix_time_nanos() {
1198        assert_eq!(
1199            FileTime::from_unix_time_nanos(-11_644_473_600_000_000_000).unwrap(),
1200            FileTime::NT_TIME_EPOCH
1201        );
1202        assert_eq!(
1203            FileTime::from_unix_time_nanos(-11_644_473_599_999_999_999).unwrap(),
1204            FileTime::NT_TIME_EPOCH
1205        );
1206        assert_eq!(
1207            FileTime::from_unix_time_nanos(-11_644_473_599_999_999_901).unwrap(),
1208            FileTime::NT_TIME_EPOCH
1209        );
1210        assert_eq!(
1211            FileTime::from_unix_time_nanos(-11_644_473_599_999_999_900).unwrap(),
1212            FileTime::new(1)
1213        );
1214        assert_eq!(
1215            FileTime::from_unix_time_nanos(-11_644_473_599_000_000_100).unwrap(),
1216            FileTime::new(FILE_TIMES_PER_SEC - 1)
1217        );
1218        assert_eq!(
1219            FileTime::from_unix_time_nanos(-11_644_473_599_000_000_099).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_001).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_000).unwrap(),
1228            FileTime::new(FILE_TIMES_PER_SEC)
1229        );
1230        assert_eq!(
1231            FileTime::from_unix_time_nanos(i128::default() - 100).unwrap(),
1232            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
1233        );
1234        assert_eq!(
1235            FileTime::from_unix_time_nanos(i128::default() - 99).unwrap(),
1236            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
1237        );
1238        assert_eq!(
1239            FileTime::from_unix_time_nanos(i128::default() - 1).unwrap(),
1240            FileTime::UNIX_EPOCH - Duration::from_nanos(100)
1241        );
1242        assert_eq!(
1243            FileTime::from_unix_time_nanos(i128::default()).unwrap(),
1244            FileTime::UNIX_EPOCH
1245        );
1246        assert_eq!(
1247            FileTime::from_unix_time_nanos(i128::default() + 1).unwrap(),
1248            FileTime::UNIX_EPOCH
1249        );
1250        assert_eq!(
1251            FileTime::from_unix_time_nanos(i128::default() + 99).unwrap(),
1252            FileTime::UNIX_EPOCH
1253        );
1254        assert_eq!(
1255            FileTime::from_unix_time_nanos(i128::default() + 100).unwrap(),
1256            FileTime::UNIX_EPOCH + Duration::from_nanos(100)
1257        );
1258        assert_eq!(
1259            FileTime::from_unix_time_nanos(910_692_730_085_477_580_700).unwrap(),
1260            FileTime::SIGNED_MAX
1261        );
1262        assert_eq!(
1263            FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_500).unwrap(),
1264            FileTime::MAX
1265        );
1266    }
1267
1268    #[cfg(feature = "std")]
1269    #[proptest]
1270    fn from_unix_time_nanos_roundtrip(
1271        #[strategy(-11_644_473_600_000_000_000..=1_833_029_933_770_955_161_500_i128)] ts: i128,
1272    ) {
1273        prop_assert!(FileTime::from_unix_time_nanos(ts).is_ok());
1274    }
1275
1276    #[test]
1277    fn from_unix_time_nanos_with_too_big_date_time() {
1278        assert_eq!(
1279            FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_501).unwrap_err(),
1280            FileTimeRangeErrorKind::Overflow.into()
1281        );
1282        assert_eq!(
1283            FileTime::from_unix_time_nanos(i128::MAX).unwrap_err(),
1284            FileTimeRangeErrorKind::Overflow.into()
1285        );
1286    }
1287
1288    #[cfg(feature = "std")]
1289    #[proptest]
1290    fn from_unix_time_nanos_with_too_big_date_time_roundtrip(
1291        #[strategy(1_833_029_933_770_955_161_501_i128..)] ts: i128,
1292    ) {
1293        prop_assert_eq!(
1294            FileTime::from_unix_time_nanos(ts).unwrap_err(),
1295            FileTimeRangeErrorKind::Overflow.into()
1296        );
1297    }
1298}