nt_time/file_time/
cmp.rs

1// SPDX-FileCopyrightText: 2023 Shun Sakai
2//
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5//! Utilities for comparing and ordering values.
6
7use core::cmp::Ordering;
8
9use time::OffsetDateTime;
10
11use super::FileTime;
12
13#[cfg(feature = "std")]
14impl PartialEq<FileTime> for std::time::SystemTime {
15    #[inline]
16    fn eq(&self, other: &FileTime) -> bool {
17        self == &Self::from(*other)
18    }
19}
20
21#[cfg(feature = "std")]
22impl PartialEq<std::time::SystemTime> for FileTime {
23    #[inline]
24    fn eq(&self, other: &std::time::SystemTime) -> bool {
25        use std::time::SystemTime;
26
27        &SystemTime::from(*self) == other
28    }
29}
30
31impl PartialEq<FileTime> for OffsetDateTime {
32    #[inline]
33    fn eq(&self, other: &FileTime) -> bool {
34        self == &Self::try_from(*other).expect("`other` is out of range for `OffsetDateTime`")
35    }
36}
37
38impl PartialEq<OffsetDateTime> for FileTime {
39    #[inline]
40    fn eq(&self, other: &OffsetDateTime) -> bool {
41        &OffsetDateTime::try_from(*self).expect("`self` is out of range for `OffsetDateTime`")
42            == other
43    }
44}
45
46#[cfg(feature = "chrono")]
47impl PartialEq<FileTime> for chrono::DateTime<chrono::Utc> {
48    #[inline]
49    fn eq(&self, other: &FileTime) -> bool {
50        self == &Self::from(*other)
51    }
52}
53
54#[cfg(feature = "chrono")]
55impl PartialEq<chrono::DateTime<chrono::Utc>> for FileTime {
56    #[inline]
57    fn eq(&self, other: &chrono::DateTime<chrono::Utc>) -> bool {
58        use chrono::{DateTime, Utc};
59
60        &DateTime::<Utc>::from(*self) == other
61    }
62}
63
64#[cfg(feature = "jiff")]
65impl PartialEq<FileTime> for jiff::Timestamp {
66    #[inline]
67    fn eq(&self, other: &FileTime) -> bool {
68        self == &Self::try_from(*other).expect("`other` is out of range for `Timestamp`")
69    }
70}
71
72#[cfg(feature = "jiff")]
73impl PartialEq<jiff::Timestamp> for FileTime {
74    #[inline]
75    fn eq(&self, other: &jiff::Timestamp) -> bool {
76        use jiff::Timestamp;
77
78        &Timestamp::try_from(*self).expect("`self` is out of range for `Timestamp`") == other
79    }
80}
81
82#[cfg(feature = "std")]
83impl PartialOrd<FileTime> for std::time::SystemTime {
84    #[inline]
85    fn partial_cmp(&self, other: &FileTime) -> Option<Ordering> {
86        self.partial_cmp(&Self::from(*other))
87    }
88}
89
90#[cfg(feature = "std")]
91impl PartialOrd<std::time::SystemTime> for FileTime {
92    #[inline]
93    fn partial_cmp(&self, other: &std::time::SystemTime) -> Option<Ordering> {
94        use std::time::SystemTime;
95
96        SystemTime::from(*self).partial_cmp(other)
97    }
98}
99
100impl PartialOrd<FileTime> for OffsetDateTime {
101    #[inline]
102    fn partial_cmp(&self, other: &FileTime) -> Option<Ordering> {
103        self.partial_cmp(
104            &Self::try_from(*other).expect("`other` is out of range for `OffsetDateTime`"),
105        )
106    }
107}
108
109impl PartialOrd<OffsetDateTime> for FileTime {
110    #[inline]
111    fn partial_cmp(&self, other: &OffsetDateTime) -> Option<Ordering> {
112        OffsetDateTime::try_from(*self)
113            .expect("`self` is out of range for `OffsetDateTime`")
114            .partial_cmp(other)
115    }
116}
117
118#[cfg(feature = "chrono")]
119impl PartialOrd<FileTime> for chrono::DateTime<chrono::Utc> {
120    #[inline]
121    fn partial_cmp(&self, other: &FileTime) -> Option<Ordering> {
122        self.partial_cmp(&Self::from(*other))
123    }
124}
125
126#[cfg(feature = "chrono")]
127impl PartialOrd<chrono::DateTime<chrono::Utc>> for FileTime {
128    #[inline]
129    fn partial_cmp(&self, other: &chrono::DateTime<chrono::Utc>) -> Option<Ordering> {
130        use chrono::{DateTime, Utc};
131
132        DateTime::<Utc>::from(*self).partial_cmp(other)
133    }
134}
135
136#[cfg(feature = "jiff")]
137impl PartialOrd<FileTime> for jiff::Timestamp {
138    #[inline]
139    fn partial_cmp(&self, other: &FileTime) -> Option<Ordering> {
140        self.partial_cmp(&Self::try_from(*other).expect("`other` is out of range for `Timestamp`"))
141    }
142}
143
144#[cfg(feature = "jiff")]
145impl PartialOrd<jiff::Timestamp> for FileTime {
146    #[inline]
147    fn partial_cmp(&self, other: &jiff::Timestamp) -> Option<Ordering> {
148        use jiff::Timestamp;
149
150        Timestamp::try_from(*self)
151            .expect("`self` is out of range for `Timestamp`")
152            .partial_cmp(other)
153    }
154}
155
156#[cfg(test)]
157mod tests {
158    use time::macros::datetime;
159
160    use super::*;
161
162    #[test]
163    fn equality() {
164        assert_eq!(FileTime::NT_TIME_EPOCH, FileTime::NT_TIME_EPOCH);
165        assert_ne!(FileTime::NT_TIME_EPOCH, FileTime::UNIX_EPOCH);
166        assert_ne!(FileTime::NT_TIME_EPOCH, FileTime::MAX);
167        assert_ne!(FileTime::UNIX_EPOCH, FileTime::NT_TIME_EPOCH);
168        assert_eq!(FileTime::UNIX_EPOCH, FileTime::UNIX_EPOCH);
169        assert_ne!(FileTime::UNIX_EPOCH, FileTime::MAX);
170        assert_ne!(FileTime::MAX, FileTime::NT_TIME_EPOCH);
171        assert_ne!(FileTime::MAX, FileTime::UNIX_EPOCH);
172        assert_eq!(FileTime::MAX, FileTime::MAX);
173    }
174
175    #[test]
176    fn order() {
177        assert!(FileTime::UNIX_EPOCH < FileTime::MAX);
178        assert_eq!(
179            FileTime::UNIX_EPOCH.cmp(&FileTime::UNIX_EPOCH),
180            Ordering::Equal
181        );
182        assert!(FileTime::UNIX_EPOCH > FileTime::NT_TIME_EPOCH);
183    }
184
185    #[cfg(feature = "std")]
186    #[test]
187    fn equality_system_time_and_file_time() {
188        use std::time::{Duration, SystemTime};
189
190        assert_eq!(
191            (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700)),
192            FileTime::new(9_223_372_036_854_775_807)
193        );
194        assert_ne!(
195            (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700)),
196            FileTime::new(9_223_372_036_854_775_806)
197        );
198        assert_eq!(SystemTime::UNIX_EPOCH, FileTime::UNIX_EPOCH);
199        assert_ne!(SystemTime::UNIX_EPOCH, FileTime::NT_TIME_EPOCH);
200    }
201
202    #[cfg(feature = "std")]
203    #[test]
204    fn equality_file_time_and_system_time() {
205        use std::time::{Duration, SystemTime};
206
207        assert_eq!(
208            FileTime::new(9_223_372_036_854_775_807),
209            (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700))
210        );
211        assert_ne!(
212            FileTime::new(9_223_372_036_854_775_806),
213            (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700))
214        );
215        assert_eq!(FileTime::UNIX_EPOCH, SystemTime::UNIX_EPOCH);
216        assert_ne!(FileTime::NT_TIME_EPOCH, SystemTime::UNIX_EPOCH);
217    }
218
219    #[test]
220    fn equality_offset_date_time_and_file_time() {
221        assert_eq!(
222            datetime!(9999-12-31 23:59:59.999_999_900 UTC),
223            FileTime::new(2_650_467_743_999_999_999)
224        );
225        assert_ne!(
226            datetime!(9999-12-31 23:59:59.999_999_900 UTC),
227            FileTime::NT_TIME_EPOCH
228        );
229        assert_ne!(
230            datetime!(1601-01-01 00:00 UTC),
231            FileTime::new(2_650_467_743_999_999_999)
232        );
233        assert_eq!(datetime!(1601-01-01 00:00 UTC), FileTime::NT_TIME_EPOCH);
234    }
235
236    #[test]
237    fn equality_file_time_and_offset_date_time() {
238        assert_eq!(
239            FileTime::new(2_650_467_743_999_999_999),
240            datetime!(9999-12-31 23:59:59.999_999_900 UTC)
241        );
242        assert_ne!(
243            FileTime::NT_TIME_EPOCH,
244            datetime!(9999-12-31 23:59:59.999_999_900 UTC)
245        );
246        assert_ne!(
247            FileTime::new(2_650_467_743_999_999_999),
248            datetime!(1601-01-01 00:00 UTC)
249        );
250        assert_eq!(FileTime::NT_TIME_EPOCH, datetime!(1601-01-01 00:00 UTC));
251    }
252
253    #[cfg(feature = "chrono")]
254    #[test]
255    fn equality_chrono_date_time_and_file_time() {
256        use chrono::{DateTime, Utc};
257
258        assert_eq!(
259            "+60056-05-28 05:36:10.955161500 UTC"
260                .parse::<DateTime<Utc>>()
261                .unwrap(),
262            FileTime::MAX
263        );
264        assert_ne!(
265            "+60056-05-28 05:36:10.955161500 UTC"
266                .parse::<DateTime<Utc>>()
267                .unwrap(),
268            FileTime::NT_TIME_EPOCH
269        );
270        assert_ne!(
271            "1601-01-01 00:00:00 UTC".parse::<DateTime<Utc>>().unwrap(),
272            FileTime::MAX
273        );
274        assert_eq!(
275            "1601-01-01 00:00:00 UTC".parse::<DateTime<Utc>>().unwrap(),
276            FileTime::NT_TIME_EPOCH
277        );
278    }
279
280    #[cfg(feature = "chrono")]
281    #[test]
282    fn equality_file_time_and_chrono_date_time() {
283        use chrono::{DateTime, Utc};
284
285        assert_eq!(
286            FileTime::MAX,
287            "+60056-05-28 05:36:10.955161500 UTC"
288                .parse::<DateTime<Utc>>()
289                .unwrap()
290        );
291        assert_ne!(
292            FileTime::NT_TIME_EPOCH,
293            "+60056-05-28 05:36:10.955161500 UTC"
294                .parse::<DateTime<Utc>>()
295                .unwrap()
296        );
297        assert_ne!(
298            FileTime::MAX,
299            "1601-01-01 00:00:00 UTC".parse::<DateTime<Utc>>().unwrap()
300        );
301        assert_eq!(
302            FileTime::NT_TIME_EPOCH,
303            "1601-01-01 00:00:00 UTC".parse::<DateTime<Utc>>().unwrap()
304        );
305    }
306
307    #[cfg(feature = "jiff")]
308    #[test]
309    fn equality_jiff_timestamp_and_file_time() {
310        use jiff::{Timestamp, ToSpan};
311
312        assert_eq!(
313            Timestamp::MAX - 99.nanoseconds(),
314            FileTime::new(2_650_466_808_009_999_999)
315        );
316        assert_ne!(Timestamp::MAX - 99.nanoseconds(), FileTime::NT_TIME_EPOCH);
317        assert_ne!(
318            Timestamp::from_second(-11_644_473_600).unwrap(),
319            FileTime::new(2_650_466_808_009_999_999)
320        );
321        assert_eq!(
322            Timestamp::from_second(-11_644_473_600).unwrap(),
323            FileTime::NT_TIME_EPOCH
324        );
325    }
326
327    #[cfg(feature = "jiff")]
328    #[test]
329    fn equality_file_time_and_jiff_timestamp() {
330        use jiff::{Timestamp, ToSpan};
331
332        assert_eq!(
333            FileTime::new(2_650_466_808_009_999_999),
334            Timestamp::MAX - 99.nanoseconds()
335        );
336        assert_ne!(FileTime::NT_TIME_EPOCH, Timestamp::MAX - 99.nanoseconds());
337        assert_ne!(
338            FileTime::new(2_650_466_808_009_999_999),
339            Timestamp::from_second(-11_644_473_600).unwrap()
340        );
341        assert_eq!(
342            FileTime::NT_TIME_EPOCH,
343            Timestamp::from_second(-11_644_473_600).unwrap()
344        );
345    }
346
347    #[cfg(feature = "std")]
348    #[test]
349    fn order_system_time_and_file_time() {
350        use std::time::SystemTime;
351
352        assert!(SystemTime::UNIX_EPOCH < FileTime::new(9_223_372_036_854_775_807));
353        assert_eq!(
354            SystemTime::UNIX_EPOCH.partial_cmp(&FileTime::UNIX_EPOCH),
355            Some(Ordering::Equal)
356        );
357        assert!(SystemTime::UNIX_EPOCH > FileTime::NT_TIME_EPOCH);
358    }
359
360    #[cfg(feature = "std")]
361    #[test]
362    fn order_file_time_and_system_time() {
363        use std::time::{Duration, SystemTime};
364
365        assert!(
366            FileTime::UNIX_EPOCH
367                < (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700))
368        );
369        assert_eq!(
370            FileTime::UNIX_EPOCH.partial_cmp(&SystemTime::UNIX_EPOCH),
371            Some(Ordering::Equal)
372        );
373        assert!(
374            FileTime::UNIX_EPOCH
375                > (SystemTime::UNIX_EPOCH - (FileTime::UNIX_EPOCH - FileTime::NT_TIME_EPOCH))
376        );
377    }
378
379    #[test]
380    fn order_offset_date_time_and_file_time() {
381        assert!(OffsetDateTime::UNIX_EPOCH < FileTime::new(2_650_467_743_999_999_999));
382        assert_eq!(
383            OffsetDateTime::UNIX_EPOCH.partial_cmp(&FileTime::UNIX_EPOCH),
384            Some(Ordering::Equal)
385        );
386        assert!(OffsetDateTime::UNIX_EPOCH > FileTime::NT_TIME_EPOCH);
387    }
388
389    #[test]
390    fn order_file_time_and_offset_date_time() {
391        assert!(FileTime::UNIX_EPOCH < datetime!(9999-12-31 23:59:59.999_999_900 UTC));
392        assert_eq!(
393            FileTime::UNIX_EPOCH.partial_cmp(&OffsetDateTime::UNIX_EPOCH),
394            Some(Ordering::Equal)
395        );
396        assert!(FileTime::UNIX_EPOCH > datetime!(1601-01-01 00:00 UTC));
397    }
398
399    #[cfg(feature = "chrono")]
400    #[test]
401    fn order_chrono_date_time_and_file_time() {
402        use chrono::{DateTime, Utc};
403
404        assert!(DateTime::<Utc>::UNIX_EPOCH < FileTime::MAX);
405        assert_eq!(
406            DateTime::<Utc>::UNIX_EPOCH.partial_cmp(&FileTime::UNIX_EPOCH),
407            Some(Ordering::Equal)
408        );
409        assert!(DateTime::<Utc>::UNIX_EPOCH > FileTime::NT_TIME_EPOCH);
410    }
411
412    #[cfg(feature = "chrono")]
413    #[test]
414    fn order_file_time_and_chrono_date_time() {
415        use chrono::{DateTime, Utc};
416
417        assert!(
418            FileTime::UNIX_EPOCH
419                < "+60056-05-28 05:36:10.955161500 UTC"
420                    .parse::<DateTime<Utc>>()
421                    .unwrap()
422        );
423        assert_eq!(
424            FileTime::UNIX_EPOCH.partial_cmp(&DateTime::<Utc>::UNIX_EPOCH),
425            Some(Ordering::Equal)
426        );
427        assert!(FileTime::UNIX_EPOCH > "1601-01-01 00:00:00 UTC".parse::<DateTime<Utc>>().unwrap());
428    }
429
430    #[cfg(feature = "jiff")]
431    #[test]
432    fn order_jiff_timestamp_and_file_time() {
433        use jiff::Timestamp;
434
435        assert!(Timestamp::UNIX_EPOCH < FileTime::new(2_650_466_808_009_999_999));
436        assert_eq!(
437            Timestamp::UNIX_EPOCH.partial_cmp(&FileTime::UNIX_EPOCH),
438            Some(Ordering::Equal)
439        );
440        assert!(Timestamp::UNIX_EPOCH > FileTime::NT_TIME_EPOCH);
441    }
442
443    #[cfg(feature = "jiff")]
444    #[test]
445    fn order_file_time_and_jiff_timestamp() {
446        use jiff::Timestamp;
447
448        assert!(FileTime::UNIX_EPOCH < Timestamp::MAX);
449        assert_eq!(
450            FileTime::UNIX_EPOCH.partial_cmp(&Timestamp::UNIX_EPOCH),
451            Some(Ordering::Equal)
452        );
453        assert!(FileTime::UNIX_EPOCH > Timestamp::from_second(-11_644_473_600).unwrap());
454    }
455}