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