Skip to main content

nt_time/file_time/
ops.rs

1// SPDX-FileCopyrightText: 2023 Shun Sakai
2//
3// SPDX-License-Identifier: Apache-2.0 OR MIT
4
5//! Operations for [`FileTime`].
6
7use core::{
8    ops::{Add, AddAssign, Sub, SubAssign},
9    time::Duration,
10};
11#[cfg(feature = "std")]
12use std::time::SystemTime;
13
14#[cfg(feature = "chrono")]
15use chrono::{DateTime, TimeDelta, Utc};
16#[cfg(feature = "jiff")]
17use jiff::{Span, Timestamp};
18use time::UtcDateTime;
19
20use super::FileTime;
21
22impl FileTime {
23    /// Computes `self + rhs`, returning [`None`] if overflow occurred.
24    ///
25    /// <div class="warning">
26    ///
27    /// The part of `rhs` less than 100-nanosecond is truncated.
28    ///
29    /// </div>
30    ///
31    /// # Examples
32    ///
33    /// ```
34    /// # use core::time::Duration;
35    /// #
36    /// # use nt_time::FileTime;
37    /// #
38    /// assert_eq!(
39    ///     FileTime::NT_TIME_EPOCH.checked_add(Duration::from_nanos(1)),
40    ///     Some(FileTime::NT_TIME_EPOCH)
41    /// );
42    /// assert_eq!(
43    ///     FileTime::NT_TIME_EPOCH.checked_add(Duration::from_nanos(100)),
44    ///     Some(FileTime::new(1))
45    /// );
46    ///
47    /// assert_eq!(FileTime::MAX.checked_add(Duration::from_nanos(100)), None);
48    /// ```
49    pub fn checked_add(self, rhs: Duration) -> Option<Self> {
50        let duration = u64::try_from(rhs.as_nanos() / 100).ok()?;
51        self.to_raw().checked_add(duration).map(Self::new)
52    }
53
54    /// Computes `self - rhs`, returning [`None`] if the result would be
55    /// negative or if overflow occurred.
56    ///
57    /// <div class="warning">
58    ///
59    /// The part of `rhs` less than 100-nanosecond is truncated.
60    ///
61    /// </div>
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// # use core::time::Duration;
67    /// #
68    /// # use nt_time::FileTime;
69    /// #
70    /// assert_eq!(
71    ///     FileTime::MAX.checked_sub(Duration::from_nanos(1)),
72    ///     Some(FileTime::MAX)
73    /// );
74    /// assert_eq!(
75    ///     FileTime::MAX.checked_sub(Duration::from_nanos(100)),
76    ///     Some(FileTime::new(u64::MAX - 1))
77    /// );
78    ///
79    /// assert_eq!(
80    ///     FileTime::NT_TIME_EPOCH.checked_sub(Duration::from_nanos(100)),
81    ///     None
82    /// );
83    /// ```
84    pub fn checked_sub(self, rhs: Duration) -> Option<Self> {
85        let duration = u64::try_from(rhs.as_nanos() / 100).ok()?;
86        self.to_raw().checked_sub(duration).map(Self::new)
87    }
88
89    /// Computes `self + rhs`, returning [`FileTime::MAX`] if overflow occurred.
90    ///
91    /// <div class="warning">
92    ///
93    /// The part of `rhs` less than 100-nanosecond is truncated.
94    ///
95    /// </div>
96    ///
97    /// # Examples
98    ///
99    /// ```
100    /// # use core::time::Duration;
101    /// #
102    /// # use nt_time::FileTime;
103    /// #
104    /// assert_eq!(
105    ///     FileTime::NT_TIME_EPOCH.saturating_add(Duration::from_nanos(1)),
106    ///     FileTime::NT_TIME_EPOCH
107    /// );
108    /// assert_eq!(
109    ///     FileTime::NT_TIME_EPOCH.saturating_add(Duration::from_nanos(100)),
110    ///     FileTime::new(1)
111    /// );
112    ///
113    /// assert_eq!(
114    ///     FileTime::MAX.saturating_add(Duration::from_nanos(100)),
115    ///     FileTime::MAX
116    /// );
117    /// ```
118    #[must_use]
119    pub fn saturating_add(self, rhs: Duration) -> Self {
120        self.checked_add(rhs).unwrap_or(Self::MAX)
121    }
122
123    /// Computes `self - rhs`, returning [`FileTime::NT_TIME_EPOCH`] if the
124    /// result would be negative or if overflow occurred.
125    ///
126    /// <div class="warning">
127    ///
128    /// The part of `rhs` less than 100-nanosecond is truncated.
129    ///
130    /// </div>
131    ///
132    /// # Examples
133    ///
134    /// ```
135    /// # use core::time::Duration;
136    /// #
137    /// # use nt_time::FileTime;
138    /// #
139    /// assert_eq!(
140    ///     FileTime::MAX.saturating_sub(Duration::from_nanos(1)),
141    ///     FileTime::MAX
142    /// );
143    /// assert_eq!(
144    ///     FileTime::MAX.saturating_sub(Duration::from_nanos(100)),
145    ///     FileTime::new(u64::MAX - 1)
146    /// );
147    ///
148    /// assert_eq!(
149    ///     FileTime::NT_TIME_EPOCH.saturating_sub(Duration::from_nanos(100)),
150    ///     FileTime::NT_TIME_EPOCH
151    /// );
152    /// ```
153    #[must_use]
154    pub fn saturating_sub(self, rhs: Duration) -> Self {
155        self.checked_sub(rhs).unwrap_or_default()
156    }
157}
158
159impl Add<Duration> for FileTime {
160    type Output = Self;
161
162    fn add(self, rhs: Duration) -> Self::Output {
163        self.checked_add(rhs)
164            .expect("overflow when adding duration to date and time")
165    }
166}
167
168impl Add<time::Duration> for FileTime {
169    type Output = Self;
170
171    fn add(self, rhs: time::Duration) -> Self::Output {
172        if rhs.is_positive() {
173            self + rhs.unsigned_abs()
174        } else {
175            self - rhs.unsigned_abs()
176        }
177    }
178}
179
180#[cfg(feature = "chrono")]
181impl Add<TimeDelta> for FileTime {
182    type Output = Self;
183
184    fn add(self, rhs: TimeDelta) -> Self::Output {
185        if rhs > TimeDelta::zero() {
186            self + rhs.abs().to_std().expect("duration is less than zero")
187        } else {
188            self - rhs.abs().to_std().expect("duration is less than zero")
189        }
190    }
191}
192
193#[cfg(feature = "jiff")]
194impl Add<Span> for FileTime {
195    type Output = Self;
196
197    fn add(self, rhs: Span) -> Self::Output {
198        if rhs.is_positive() {
199            self + Duration::try_from(rhs.abs()).expect("duration is less than zero")
200        } else {
201            self - Duration::try_from(rhs.abs()).expect("duration is less than zero")
202        }
203    }
204}
205
206impl AddAssign<Duration> for FileTime {
207    fn add_assign(&mut self, rhs: Duration) {
208        *self = *self + rhs;
209    }
210}
211
212impl AddAssign<time::Duration> for FileTime {
213    fn add_assign(&mut self, rhs: time::Duration) {
214        *self = *self + rhs;
215    }
216}
217
218#[cfg(feature = "chrono")]
219impl AddAssign<TimeDelta> for FileTime {
220    fn add_assign(&mut self, rhs: TimeDelta) {
221        *self = *self + rhs;
222    }
223}
224
225#[cfg(feature = "jiff")]
226impl AddAssign<Span> for FileTime {
227    fn add_assign(&mut self, rhs: Span) {
228        *self = *self + rhs;
229    }
230}
231
232impl Sub for FileTime {
233    type Output = Duration;
234
235    fn sub(self, rhs: Self) -> Self::Output {
236        let duration = self.to_raw() - rhs.to_raw();
237        Self::Output::from_nanos_u128(u128::from(duration) * 100)
238    }
239}
240
241impl Sub<Duration> for FileTime {
242    type Output = Self;
243
244    fn sub(self, rhs: Duration) -> Self::Output {
245        self.checked_sub(rhs)
246            .expect("overflow when subtracting duration from date and time")
247    }
248}
249
250impl Sub<time::Duration> for FileTime {
251    type Output = Self;
252
253    fn sub(self, rhs: time::Duration) -> Self::Output {
254        if rhs.is_positive() {
255            self - rhs.unsigned_abs()
256        } else {
257            self + rhs.unsigned_abs()
258        }
259    }
260}
261
262#[cfg(feature = "chrono")]
263impl Sub<TimeDelta> for FileTime {
264    type Output = Self;
265
266    fn sub(self, rhs: TimeDelta) -> Self::Output {
267        if rhs > TimeDelta::zero() {
268            self - rhs.abs().to_std().expect("duration is less than zero")
269        } else {
270            self + rhs.abs().to_std().expect("duration is less than zero")
271        }
272    }
273}
274
275#[cfg(feature = "jiff")]
276impl Sub<Span> for FileTime {
277    type Output = Self;
278
279    fn sub(self, rhs: Span) -> Self::Output {
280        if rhs.is_positive() {
281            self - Duration::try_from(rhs.abs()).expect("duration is less than zero")
282        } else {
283            self + Duration::try_from(rhs.abs()).expect("duration is less than zero")
284        }
285    }
286}
287
288#[cfg(feature = "std")]
289impl Sub<FileTime> for SystemTime {
290    type Output = Duration;
291
292    fn sub(self, rhs: FileTime) -> Self::Output {
293        self.duration_since(rhs.into())
294            .expect("RHS provided is later than LHS")
295    }
296}
297
298#[cfg(feature = "std")]
299impl Sub<SystemTime> for FileTime {
300    type Output = Duration;
301
302    fn sub(self, rhs: SystemTime) -> Self::Output {
303        SystemTime::from(self)
304            .duration_since(rhs)
305            .expect("RHS provided is later than LHS")
306    }
307}
308
309impl Sub<FileTime> for UtcDateTime {
310    type Output = time::Duration;
311
312    fn sub(self, rhs: FileTime) -> Self::Output {
313        self - Self::try_from(rhs).expect("RHS is out of range for `UtcDateTime`")
314    }
315}
316
317impl Sub<UtcDateTime> for FileTime {
318    type Output = time::Duration;
319
320    fn sub(self, rhs: UtcDateTime) -> Self::Output {
321        UtcDateTime::try_from(self).expect("LHS is out of range for `UtcDateTime`") - rhs
322    }
323}
324
325#[cfg(feature = "chrono")]
326impl Sub<FileTime> for DateTime<Utc> {
327    type Output = TimeDelta;
328
329    fn sub(self, rhs: FileTime) -> Self::Output {
330        self - Self::from(rhs)
331    }
332}
333
334#[cfg(feature = "chrono")]
335impl Sub<DateTime<Utc>> for FileTime {
336    type Output = TimeDelta;
337
338    fn sub(self, rhs: DateTime<Utc>) -> Self::Output {
339        DateTime::<Utc>::from(self) - rhs
340    }
341}
342
343#[cfg(feature = "jiff")]
344impl Sub<FileTime> for Timestamp {
345    type Output = Span;
346
347    fn sub(self, rhs: FileTime) -> Self::Output {
348        self - Self::try_from(rhs).expect("RHS is out of range for `Timestamp`")
349    }
350}
351
352#[cfg(feature = "jiff")]
353impl Sub<Timestamp> for FileTime {
354    type Output = Span;
355
356    fn sub(self, rhs: Timestamp) -> Self::Output {
357        Timestamp::try_from(self).expect("LHS is out of range for `Timestamp`") - rhs
358    }
359}
360
361impl SubAssign<Duration> for FileTime {
362    fn sub_assign(&mut self, rhs: Duration) {
363        *self = *self - rhs;
364    }
365}
366
367impl SubAssign<time::Duration> for FileTime {
368    fn sub_assign(&mut self, rhs: time::Duration) {
369        *self = *self - rhs;
370    }
371}
372
373#[cfg(feature = "chrono")]
374impl SubAssign<TimeDelta> for FileTime {
375    fn sub_assign(&mut self, rhs: TimeDelta) {
376        *self = *self - rhs;
377    }
378}
379
380#[cfg(feature = "jiff")]
381impl SubAssign<Span> for FileTime {
382    fn sub_assign(&mut self, rhs: Span) {
383        *self = *self - rhs;
384    }
385}
386
387#[cfg(test)]
388mod tests {
389    #[cfg(feature = "jiff")]
390    use jiff::ToSpan;
391    #[cfg(feature = "std")]
392    use proptest::{prop_assert, prop_assert_eq, prop_assert_ne};
393    #[cfg(feature = "std")]
394    use test_strategy::proptest;
395    use time::macros::utc_datetime;
396
397    use super::*;
398
399    #[test]
400    fn checked_add() {
401        assert_eq!(
402            FileTime::NT_TIME_EPOCH.checked_add(Duration::ZERO),
403            Some(FileTime::NT_TIME_EPOCH)
404        );
405        assert_eq!(
406            FileTime::NT_TIME_EPOCH.checked_add(Duration::from_nanos(1)),
407            Some(FileTime::NT_TIME_EPOCH)
408        );
409        assert_eq!(
410            FileTime::NT_TIME_EPOCH.checked_add(Duration::from_nanos(99)),
411            Some(FileTime::NT_TIME_EPOCH)
412        );
413        assert_eq!(
414            FileTime::NT_TIME_EPOCH.checked_add(Duration::from_nanos(100)),
415            Some(FileTime::new(1))
416        );
417
418        assert_eq!(
419            FileTime::MAX.checked_add(Duration::ZERO),
420            Some(FileTime::MAX)
421        );
422        assert_eq!(
423            FileTime::MAX.checked_add(Duration::from_nanos(1)),
424            Some(FileTime::MAX)
425        );
426        assert_eq!(
427            FileTime::MAX.checked_add(Duration::from_nanos(99)),
428            Some(FileTime::MAX)
429        );
430        assert_eq!(FileTime::MAX.checked_add(Duration::from_nanos(100)), None);
431    }
432
433    #[cfg(feature = "std")]
434    #[proptest]
435    fn checked_add_roundtrip(duration: Duration) {
436        if duration <= Duration::new(1_844_674_407_370, 955_161_500) {
437            prop_assert!(FileTime::NT_TIME_EPOCH.checked_add(duration).is_some());
438        } else {
439            prop_assert!(FileTime::NT_TIME_EPOCH.checked_add(duration).is_none());
440        }
441    }
442
443    #[test]
444    fn checked_sub() {
445        assert_eq!(
446            FileTime::MAX.checked_sub(Duration::ZERO),
447            Some(FileTime::MAX)
448        );
449        assert_eq!(
450            FileTime::MAX.checked_sub(Duration::from_nanos(1)),
451            Some(FileTime::MAX)
452        );
453        assert_eq!(
454            FileTime::MAX.checked_sub(Duration::from_nanos(99)),
455            Some(FileTime::MAX)
456        );
457        assert_eq!(
458            FileTime::MAX.checked_sub(Duration::from_nanos(100)),
459            Some(FileTime::new(u64::MAX - 1))
460        );
461
462        assert_eq!(
463            FileTime::NT_TIME_EPOCH.checked_sub(Duration::ZERO),
464            Some(FileTime::NT_TIME_EPOCH)
465        );
466        assert_eq!(
467            FileTime::NT_TIME_EPOCH.checked_sub(Duration::from_nanos(1)),
468            Some(FileTime::NT_TIME_EPOCH)
469        );
470        assert_eq!(
471            FileTime::NT_TIME_EPOCH.checked_sub(Duration::from_nanos(99)),
472            Some(FileTime::NT_TIME_EPOCH)
473        );
474        assert_eq!(
475            FileTime::NT_TIME_EPOCH.checked_sub(Duration::from_nanos(100)),
476            None
477        );
478    }
479
480    #[cfg(feature = "std")]
481    #[proptest]
482    fn checked_sub_roundtrip(duration: Duration) {
483        if duration <= Duration::new(1_844_674_407_370, 955_161_500) {
484            prop_assert!(FileTime::MAX.checked_sub(duration).is_some());
485        } else {
486            prop_assert!(FileTime::MAX.checked_sub(duration).is_none());
487        }
488    }
489
490    #[test]
491    fn saturating_add() {
492        assert_eq!(
493            FileTime::NT_TIME_EPOCH.saturating_add(Duration::ZERO),
494            FileTime::NT_TIME_EPOCH
495        );
496        assert_eq!(
497            FileTime::NT_TIME_EPOCH.saturating_add(Duration::from_nanos(1)),
498            FileTime::NT_TIME_EPOCH
499        );
500        assert_eq!(
501            FileTime::NT_TIME_EPOCH.saturating_add(Duration::from_nanos(99)),
502            FileTime::NT_TIME_EPOCH
503        );
504        assert_eq!(
505            FileTime::NT_TIME_EPOCH.saturating_add(Duration::from_nanos(100)),
506            FileTime::new(1)
507        );
508
509        assert_eq!(FileTime::MAX.saturating_add(Duration::ZERO), FileTime::MAX);
510        assert_eq!(
511            FileTime::MAX.saturating_add(Duration::from_nanos(1)),
512            FileTime::MAX
513        );
514        assert_eq!(
515            FileTime::MAX.saturating_add(Duration::from_nanos(99)),
516            FileTime::MAX
517        );
518        assert_eq!(
519            FileTime::MAX.saturating_add(Duration::from_nanos(100)),
520            FileTime::MAX
521        );
522    }
523
524    #[cfg(feature = "std")]
525    #[proptest]
526    fn saturating_add_roundtrip(duration: Duration) {
527        if duration <= Duration::new(1_844_674_407_370, 955_161_400) {
528            prop_assert_ne!(
529                FileTime::NT_TIME_EPOCH.saturating_add(duration),
530                FileTime::MAX
531            );
532        } else {
533            prop_assert_eq!(
534                FileTime::NT_TIME_EPOCH.saturating_add(duration),
535                FileTime::MAX
536            );
537        }
538    }
539
540    #[test]
541    fn saturating_sub() {
542        assert_eq!(FileTime::MAX.saturating_sub(Duration::ZERO), FileTime::MAX);
543        assert_eq!(
544            FileTime::MAX.saturating_sub(Duration::from_nanos(1)),
545            FileTime::MAX
546        );
547        assert_eq!(
548            FileTime::MAX.saturating_sub(Duration::from_nanos(99)),
549            FileTime::MAX
550        );
551        assert_eq!(
552            FileTime::MAX.saturating_sub(Duration::from_nanos(100)),
553            FileTime::new(u64::MAX - 1)
554        );
555
556        assert_eq!(
557            FileTime::NT_TIME_EPOCH.saturating_sub(Duration::ZERO),
558            FileTime::NT_TIME_EPOCH
559        );
560        assert_eq!(
561            FileTime::NT_TIME_EPOCH.saturating_sub(Duration::from_nanos(1)),
562            FileTime::NT_TIME_EPOCH
563        );
564        assert_eq!(
565            FileTime::NT_TIME_EPOCH.saturating_sub(Duration::from_nanos(99)),
566            FileTime::NT_TIME_EPOCH
567        );
568        assert_eq!(
569            FileTime::NT_TIME_EPOCH.saturating_sub(Duration::from_nanos(100)),
570            FileTime::NT_TIME_EPOCH
571        );
572    }
573
574    #[cfg(feature = "std")]
575    #[proptest]
576    fn saturating_sub_roundtrip(duration: Duration) {
577        if duration <= Duration::new(1_844_674_407_370, 955_161_400) {
578            prop_assert_ne!(
579                FileTime::MAX.saturating_sub(duration),
580                FileTime::NT_TIME_EPOCH
581            );
582        } else {
583            prop_assert_eq!(
584                FileTime::MAX.saturating_sub(duration),
585                FileTime::NT_TIME_EPOCH
586            );
587        }
588    }
589
590    #[test]
591    fn add_std_duration() {
592        assert_eq!(
593            FileTime::NT_TIME_EPOCH + Duration::ZERO,
594            FileTime::NT_TIME_EPOCH
595        );
596        assert_eq!(
597            FileTime::NT_TIME_EPOCH + Duration::from_nanos(1),
598            FileTime::NT_TIME_EPOCH
599        );
600        assert_eq!(
601            FileTime::NT_TIME_EPOCH + Duration::from_nanos(99),
602            FileTime::NT_TIME_EPOCH
603        );
604        assert_eq!(
605            FileTime::NT_TIME_EPOCH + Duration::from_nanos(100),
606            FileTime::new(1)
607        );
608
609        assert_eq!(FileTime::MAX + Duration::ZERO, FileTime::MAX);
610        assert_eq!(FileTime::MAX + Duration::from_nanos(1), FileTime::MAX);
611        assert_eq!(FileTime::MAX + Duration::from_nanos(99), FileTime::MAX);
612    }
613
614    #[test]
615    #[should_panic(expected = "overflow when adding duration to date and time")]
616    fn add_std_duration_with_overflow() {
617        let _ = FileTime::MAX + Duration::from_nanos(100);
618    }
619
620    #[test]
621    fn add_positive_time_duration() {
622        assert_eq!(
623            FileTime::NT_TIME_EPOCH + time::Duration::ZERO,
624            FileTime::NT_TIME_EPOCH
625        );
626        assert_eq!(
627            FileTime::NT_TIME_EPOCH + time::Duration::NANOSECOND,
628            FileTime::NT_TIME_EPOCH
629        );
630        assert_eq!(
631            FileTime::NT_TIME_EPOCH + time::Duration::nanoseconds(99),
632            FileTime::NT_TIME_EPOCH
633        );
634        assert_eq!(
635            FileTime::NT_TIME_EPOCH + time::Duration::nanoseconds(100),
636            FileTime::new(1)
637        );
638
639        assert_eq!(FileTime::MAX + time::Duration::ZERO, FileTime::MAX);
640        assert_eq!(FileTime::MAX + time::Duration::NANOSECOND, FileTime::MAX);
641        assert_eq!(
642            FileTime::MAX + time::Duration::nanoseconds(99),
643            FileTime::MAX
644        );
645    }
646
647    #[test]
648    #[should_panic(expected = "overflow when adding duration to date and time")]
649    fn add_positive_time_duration_with_overflow() {
650        let _ = FileTime::MAX + time::Duration::nanoseconds(100);
651    }
652
653    #[test]
654    fn add_negative_time_duration() {
655        assert_eq!(FileTime::MAX + -time::Duration::ZERO, FileTime::MAX);
656        assert_eq!(FileTime::MAX + -time::Duration::NANOSECOND, FileTime::MAX);
657        assert_eq!(
658            FileTime::MAX + -time::Duration::nanoseconds(99),
659            FileTime::MAX
660        );
661        assert_eq!(
662            FileTime::MAX + -time::Duration::nanoseconds(100),
663            FileTime::new(u64::MAX - 1)
664        );
665
666        assert_eq!(
667            FileTime::NT_TIME_EPOCH + -time::Duration::ZERO,
668            FileTime::NT_TIME_EPOCH
669        );
670        assert_eq!(
671            FileTime::NT_TIME_EPOCH + -time::Duration::NANOSECOND,
672            FileTime::NT_TIME_EPOCH
673        );
674        assert_eq!(
675            FileTime::NT_TIME_EPOCH + -time::Duration::nanoseconds(99),
676            FileTime::NT_TIME_EPOCH
677        );
678    }
679
680    #[test]
681    #[should_panic(expected = "overflow when subtracting duration from date and time")]
682    fn add_negative_time_duration_with_overflow() {
683        let _ = FileTime::NT_TIME_EPOCH + -time::Duration::nanoseconds(100);
684    }
685
686    #[cfg(feature = "chrono")]
687    #[test]
688    fn add_positive_chrono_time_delta() {
689        assert_eq!(
690            FileTime::NT_TIME_EPOCH + TimeDelta::zero(),
691            FileTime::NT_TIME_EPOCH
692        );
693        assert_eq!(
694            FileTime::NT_TIME_EPOCH + TimeDelta::nanoseconds(1),
695            FileTime::NT_TIME_EPOCH
696        );
697        assert_eq!(
698            FileTime::NT_TIME_EPOCH + TimeDelta::nanoseconds(99),
699            FileTime::NT_TIME_EPOCH
700        );
701        assert_eq!(
702            FileTime::NT_TIME_EPOCH + TimeDelta::nanoseconds(100),
703            FileTime::new(1)
704        );
705
706        assert_eq!(FileTime::MAX + TimeDelta::zero(), FileTime::MAX);
707        assert_eq!(FileTime::MAX + TimeDelta::nanoseconds(1), FileTime::MAX);
708        assert_eq!(FileTime::MAX + TimeDelta::nanoseconds(99), FileTime::MAX);
709    }
710
711    #[cfg(feature = "chrono")]
712    #[test]
713    #[should_panic(expected = "overflow when adding duration to date and time")]
714    fn add_positive_chrono_time_delta_with_overflow() {
715        let _ = FileTime::MAX + TimeDelta::nanoseconds(100);
716    }
717
718    #[cfg(feature = "chrono")]
719    #[test]
720    fn add_negative_chrono_time_delta() {
721        assert_eq!(FileTime::MAX + -TimeDelta::zero(), FileTime::MAX);
722        assert_eq!(FileTime::MAX + -TimeDelta::nanoseconds(1), FileTime::MAX);
723        assert_eq!(FileTime::MAX + -TimeDelta::nanoseconds(99), FileTime::MAX);
724        assert_eq!(
725            FileTime::MAX + -TimeDelta::nanoseconds(100),
726            FileTime::new(u64::MAX - 1)
727        );
728
729        assert_eq!(
730            FileTime::NT_TIME_EPOCH + -TimeDelta::zero(),
731            FileTime::NT_TIME_EPOCH
732        );
733        assert_eq!(
734            FileTime::NT_TIME_EPOCH + -TimeDelta::nanoseconds(1),
735            FileTime::NT_TIME_EPOCH
736        );
737        assert_eq!(
738            FileTime::NT_TIME_EPOCH + -TimeDelta::nanoseconds(99),
739            FileTime::NT_TIME_EPOCH
740        );
741    }
742
743    #[cfg(feature = "chrono")]
744    #[test]
745    #[should_panic(expected = "overflow when subtracting duration from date and time")]
746    fn add_negative_chrono_time_delta_with_overflow() {
747        let _ = FileTime::NT_TIME_EPOCH + -TimeDelta::nanoseconds(100);
748    }
749
750    #[cfg(feature = "jiff")]
751    #[test]
752    fn add_positive_jiff_span() {
753        assert_eq!(
754            FileTime::NT_TIME_EPOCH + Span::new(),
755            FileTime::NT_TIME_EPOCH
756        );
757        assert_eq!(
758            FileTime::NT_TIME_EPOCH + 1.nanosecond(),
759            FileTime::NT_TIME_EPOCH
760        );
761        assert_eq!(
762            FileTime::NT_TIME_EPOCH + 99.nanoseconds(),
763            FileTime::NT_TIME_EPOCH
764        );
765        assert_eq!(
766            FileTime::NT_TIME_EPOCH + 100.nanoseconds(),
767            FileTime::new(1)
768        );
769
770        assert_eq!(FileTime::MAX + Span::new(), FileTime::MAX);
771        assert_eq!(FileTime::MAX + 1.nanosecond(), FileTime::MAX);
772        assert_eq!(FileTime::MAX + 99.nanoseconds(), FileTime::MAX);
773    }
774
775    #[cfg(feature = "jiff")]
776    #[test]
777    #[should_panic(expected = "overflow when adding duration to date and time")]
778    fn add_positive_jiff_span_with_overflow() {
779        let _ = FileTime::MAX + 100.nanoseconds();
780    }
781
782    #[cfg(feature = "jiff")]
783    #[test]
784    fn add_negative_jiff_span() {
785        assert_eq!(FileTime::MAX + -Span::new(), FileTime::MAX);
786        assert_eq!(FileTime::MAX + -(1.nanosecond()), FileTime::MAX);
787        assert_eq!(FileTime::MAX + -(99.nanoseconds()), FileTime::MAX);
788        assert_eq!(
789            FileTime::MAX + -(100.nanoseconds()),
790            FileTime::new(u64::MAX - 1)
791        );
792
793        assert_eq!(
794            FileTime::NT_TIME_EPOCH + -Span::new(),
795            FileTime::NT_TIME_EPOCH
796        );
797        assert_eq!(
798            FileTime::NT_TIME_EPOCH + -(1.nanosecond()),
799            FileTime::NT_TIME_EPOCH
800        );
801        assert_eq!(
802            FileTime::NT_TIME_EPOCH + -(99.nanoseconds()),
803            FileTime::NT_TIME_EPOCH
804        );
805    }
806
807    #[cfg(feature = "jiff")]
808    #[test]
809    #[should_panic(expected = "overflow when subtracting duration from date and time")]
810    fn add_negative_jiff_span_with_overflow() {
811        let _ = FileTime::NT_TIME_EPOCH + -(100.nanoseconds());
812    }
813
814    #[test]
815    fn add_assign_std_duration() {
816        {
817            let mut ft = FileTime::NT_TIME_EPOCH;
818            ft += Duration::ZERO;
819            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
820        }
821        {
822            let mut ft = FileTime::NT_TIME_EPOCH;
823            ft += Duration::from_nanos(1);
824            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
825        }
826        {
827            let mut ft = FileTime::NT_TIME_EPOCH;
828            ft += Duration::from_nanos(99);
829            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
830        }
831        {
832            let mut ft = FileTime::NT_TIME_EPOCH;
833            ft += Duration::from_nanos(100);
834            assert_eq!(ft, FileTime::new(1));
835        }
836
837        {
838            let mut ft = FileTime::MAX;
839            ft += Duration::ZERO;
840            assert_eq!(ft, FileTime::MAX);
841        }
842        {
843            let mut ft = FileTime::MAX;
844            ft += Duration::from_nanos(1);
845            assert_eq!(ft, FileTime::MAX);
846        }
847        {
848            let mut ft = FileTime::MAX;
849            ft += Duration::from_nanos(99);
850            assert_eq!(ft, FileTime::MAX);
851        }
852    }
853
854    #[test]
855    #[should_panic(expected = "overflow when adding duration to date and time")]
856    fn add_assign_std_duration_with_overflow() {
857        let mut ft = FileTime::MAX;
858        ft += Duration::from_nanos(100);
859    }
860
861    #[test]
862    fn add_assign_positive_time_duration() {
863        {
864            let mut ft = FileTime::NT_TIME_EPOCH;
865            ft += time::Duration::ZERO;
866            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
867        }
868        {
869            let mut ft = FileTime::NT_TIME_EPOCH;
870            ft += time::Duration::NANOSECOND;
871            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
872        }
873        {
874            let mut ft = FileTime::NT_TIME_EPOCH;
875            ft += time::Duration::nanoseconds(99);
876            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
877        }
878        {
879            let mut ft = FileTime::NT_TIME_EPOCH;
880            ft += time::Duration::nanoseconds(100);
881            assert_eq!(ft, FileTime::new(1));
882        }
883
884        {
885            let mut ft = FileTime::MAX;
886            ft += time::Duration::ZERO;
887            assert_eq!(ft, FileTime::MAX);
888        }
889        {
890            let mut ft = FileTime::MAX;
891            ft += time::Duration::NANOSECOND;
892            assert_eq!(ft, FileTime::MAX);
893        }
894        {
895            let mut ft = FileTime::MAX;
896            ft += time::Duration::nanoseconds(99);
897            assert_eq!(ft, FileTime::MAX);
898        }
899    }
900
901    #[test]
902    #[should_panic(expected = "overflow when adding duration to date and time")]
903    fn add_assign_positive_time_duration_with_overflow() {
904        let mut ft = FileTime::MAX;
905        ft += time::Duration::nanoseconds(100);
906    }
907
908    #[test]
909    fn add_assign_negative_time_duration() {
910        {
911            let mut ft = FileTime::MAX;
912            ft += -time::Duration::ZERO;
913            assert_eq!(ft, FileTime::MAX);
914        }
915        {
916            let mut ft = FileTime::MAX;
917            ft += -time::Duration::NANOSECOND;
918            assert_eq!(ft, FileTime::MAX);
919        }
920        {
921            let mut ft = FileTime::MAX;
922            ft += -time::Duration::nanoseconds(99);
923            assert_eq!(ft, FileTime::MAX);
924        }
925        {
926            let mut ft = FileTime::MAX;
927            ft += -time::Duration::nanoseconds(100);
928            assert_eq!(ft, FileTime::new(u64::MAX - 1));
929        }
930
931        {
932            let mut ft = FileTime::NT_TIME_EPOCH;
933            ft += -time::Duration::ZERO;
934            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
935        }
936        {
937            let mut ft = FileTime::NT_TIME_EPOCH;
938            ft += -time::Duration::NANOSECOND;
939            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
940        }
941        {
942            let mut ft = FileTime::NT_TIME_EPOCH;
943            ft += -time::Duration::nanoseconds(99);
944            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
945        }
946    }
947
948    #[test]
949    #[should_panic(expected = "overflow when subtracting duration from date and time")]
950    fn add_assign_negative_time_duration_with_overflow() {
951        let mut ft = FileTime::NT_TIME_EPOCH;
952        ft += -time::Duration::nanoseconds(100);
953    }
954
955    #[cfg(feature = "chrono")]
956    #[test]
957    fn add_assign_positive_chrono_time_delta() {
958        {
959            let mut ft = FileTime::NT_TIME_EPOCH;
960            ft += TimeDelta::zero();
961            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
962        }
963        {
964            let mut ft = FileTime::NT_TIME_EPOCH;
965            ft += TimeDelta::nanoseconds(1);
966            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
967        }
968        {
969            let mut ft = FileTime::NT_TIME_EPOCH;
970            ft += TimeDelta::nanoseconds(99);
971            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
972        }
973        {
974            let mut ft = FileTime::NT_TIME_EPOCH;
975            ft += TimeDelta::nanoseconds(100);
976            assert_eq!(ft, FileTime::new(1));
977        }
978
979        {
980            let mut ft = FileTime::MAX;
981            ft += TimeDelta::zero();
982            assert_eq!(ft, FileTime::MAX);
983        }
984        {
985            let mut ft = FileTime::MAX;
986            ft += TimeDelta::nanoseconds(1);
987            assert_eq!(ft, FileTime::MAX);
988        }
989        {
990            let mut ft = FileTime::MAX;
991            ft += TimeDelta::nanoseconds(99);
992            assert_eq!(ft, FileTime::MAX);
993        }
994    }
995
996    #[cfg(feature = "chrono")]
997    #[test]
998    #[should_panic(expected = "overflow when adding duration to date and time")]
999    fn add_assign_positive_chrono_time_delta_with_overflow() {
1000        let mut ft = FileTime::MAX;
1001        ft += TimeDelta::nanoseconds(100);
1002    }
1003
1004    #[cfg(feature = "chrono")]
1005    #[test]
1006    fn add_assign_negative_chrono_time_delta() {
1007        {
1008            let mut ft = FileTime::MAX;
1009            ft += -TimeDelta::zero();
1010            assert_eq!(ft, FileTime::MAX);
1011        }
1012        {
1013            let mut ft = FileTime::MAX;
1014            ft += -TimeDelta::nanoseconds(1);
1015            assert_eq!(ft, FileTime::MAX);
1016        }
1017        {
1018            let mut ft = FileTime::MAX;
1019            ft += -TimeDelta::nanoseconds(99);
1020            assert_eq!(ft, FileTime::MAX);
1021        }
1022        {
1023            let mut ft = FileTime::MAX;
1024            ft += -TimeDelta::nanoseconds(100);
1025            assert_eq!(ft, FileTime::new(u64::MAX - 1));
1026        }
1027
1028        {
1029            let mut ft = FileTime::NT_TIME_EPOCH;
1030            ft += -TimeDelta::zero();
1031            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1032        }
1033        {
1034            let mut ft = FileTime::NT_TIME_EPOCH;
1035            ft += -TimeDelta::nanoseconds(1);
1036            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1037        }
1038        {
1039            let mut ft = FileTime::NT_TIME_EPOCH;
1040            ft += -TimeDelta::nanoseconds(99);
1041            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1042        }
1043    }
1044
1045    #[cfg(feature = "chrono")]
1046    #[test]
1047    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1048    fn add_assign_negative_chrono_time_delta_with_overflow() {
1049        let mut ft = FileTime::NT_TIME_EPOCH;
1050        ft += -TimeDelta::nanoseconds(100);
1051    }
1052
1053    #[cfg(feature = "jiff")]
1054    #[test]
1055    fn add_assign_positive_jiff_span() {
1056        {
1057            let mut ft = FileTime::NT_TIME_EPOCH;
1058            ft += Span::new();
1059            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1060        }
1061        {
1062            let mut ft = FileTime::NT_TIME_EPOCH;
1063            ft += 1.nanosecond();
1064            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1065        }
1066        {
1067            let mut ft = FileTime::NT_TIME_EPOCH;
1068            ft += 99.nanoseconds();
1069            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1070        }
1071        {
1072            let mut ft = FileTime::NT_TIME_EPOCH;
1073            ft += 100.nanoseconds();
1074            assert_eq!(ft, FileTime::new(1));
1075        }
1076
1077        {
1078            let mut ft = FileTime::MAX;
1079            ft += Span::new();
1080            assert_eq!(ft, FileTime::MAX);
1081        }
1082        {
1083            let mut ft = FileTime::MAX;
1084            ft += 1.nanosecond();
1085            assert_eq!(ft, FileTime::MAX);
1086        }
1087        {
1088            let mut ft = FileTime::MAX;
1089            ft += 99.nanoseconds();
1090            assert_eq!(ft, FileTime::MAX);
1091        }
1092    }
1093
1094    #[cfg(feature = "jiff")]
1095    #[test]
1096    #[should_panic(expected = "overflow when adding duration to date and time")]
1097    fn add_assign_positive_jiff_span_with_overflow() {
1098        let mut ft = FileTime::MAX;
1099        ft += 100.nanoseconds();
1100    }
1101
1102    #[cfg(feature = "jiff")]
1103    #[test]
1104    fn add_assign_negative_jiff_span() {
1105        {
1106            let mut ft = FileTime::MAX;
1107            ft += -Span::new();
1108            assert_eq!(ft, FileTime::MAX);
1109        }
1110        {
1111            let mut ft = FileTime::MAX;
1112            ft += -(1.nanosecond());
1113            assert_eq!(ft, FileTime::MAX);
1114        }
1115        {
1116            let mut ft = FileTime::MAX;
1117            ft += -(99.nanoseconds());
1118            assert_eq!(ft, FileTime::MAX);
1119        }
1120        {
1121            let mut ft = FileTime::MAX;
1122            ft += -(100.nanoseconds());
1123            assert_eq!(ft, FileTime::new(u64::MAX - 1));
1124        }
1125
1126        {
1127            let mut ft = FileTime::NT_TIME_EPOCH;
1128            ft += -Span::new();
1129            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1130        }
1131        {
1132            let mut ft = FileTime::NT_TIME_EPOCH;
1133            ft += -(1.nanosecond());
1134            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1135        }
1136        {
1137            let mut ft = FileTime::NT_TIME_EPOCH;
1138            ft += -(99.nanoseconds());
1139            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1140        }
1141    }
1142
1143    #[cfg(feature = "jiff")]
1144    #[test]
1145    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1146    fn add_assign_negative_jiff_span_with_overflow() {
1147        let mut ft = FileTime::NT_TIME_EPOCH;
1148        ft += -(100.nanoseconds());
1149    }
1150
1151    #[test]
1152    fn sub_file_time() {
1153        assert_eq!(FileTime::MAX - FileTime::MAX, Duration::ZERO);
1154        assert_eq!(
1155            FileTime::MAX - (FileTime::MAX - Duration::from_nanos(100)),
1156            Duration::from_nanos(100)
1157        );
1158        assert_eq!(
1159            FileTime::MAX - FileTime::NT_TIME_EPOCH,
1160            Duration::new(1_844_674_407_370, 955_161_500)
1161        );
1162    }
1163
1164    #[test]
1165    #[should_panic(expected = "attempt to subtract with overflow")]
1166    fn sub_file_time_with_overflow() {
1167        let _ = (FileTime::MAX - Duration::from_nanos(100)) - FileTime::MAX;
1168    }
1169
1170    #[test]
1171    fn sub_std_duration() {
1172        assert_eq!(FileTime::MAX - Duration::ZERO, FileTime::MAX);
1173        assert_eq!(FileTime::MAX - Duration::from_nanos(1), FileTime::MAX);
1174        assert_eq!(FileTime::MAX - Duration::from_nanos(99), FileTime::MAX);
1175        assert_eq!(
1176            FileTime::MAX - Duration::from_nanos(100),
1177            FileTime::new(u64::MAX - 1)
1178        );
1179
1180        assert_eq!(
1181            FileTime::NT_TIME_EPOCH - Duration::ZERO,
1182            FileTime::NT_TIME_EPOCH
1183        );
1184        assert_eq!(
1185            FileTime::NT_TIME_EPOCH - Duration::from_nanos(1),
1186            FileTime::NT_TIME_EPOCH
1187        );
1188        assert_eq!(
1189            FileTime::NT_TIME_EPOCH - Duration::from_nanos(99),
1190            FileTime::NT_TIME_EPOCH
1191        );
1192    }
1193
1194    #[test]
1195    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1196    fn sub_std_duration_with_overflow() {
1197        let _ = FileTime::NT_TIME_EPOCH - Duration::from_nanos(100);
1198    }
1199
1200    #[test]
1201    fn sub_positive_time_duration() {
1202        assert_eq!(FileTime::MAX - time::Duration::ZERO, FileTime::MAX);
1203        assert_eq!(FileTime::MAX - time::Duration::NANOSECOND, FileTime::MAX);
1204        assert_eq!(
1205            FileTime::MAX - time::Duration::nanoseconds(99),
1206            FileTime::MAX
1207        );
1208        assert_eq!(
1209            FileTime::MAX - time::Duration::nanoseconds(100),
1210            FileTime::new(u64::MAX - 1)
1211        );
1212
1213        assert_eq!(
1214            FileTime::NT_TIME_EPOCH - time::Duration::ZERO,
1215            FileTime::NT_TIME_EPOCH
1216        );
1217        assert_eq!(
1218            FileTime::NT_TIME_EPOCH - time::Duration::NANOSECOND,
1219            FileTime::NT_TIME_EPOCH
1220        );
1221        assert_eq!(
1222            FileTime::NT_TIME_EPOCH - time::Duration::nanoseconds(99),
1223            FileTime::NT_TIME_EPOCH
1224        );
1225    }
1226
1227    #[test]
1228    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1229    fn sub_positive_time_duration_with_overflow() {
1230        let _ = FileTime::NT_TIME_EPOCH - time::Duration::nanoseconds(100);
1231    }
1232
1233    #[test]
1234    fn sub_negative_time_duration() {
1235        assert_eq!(
1236            FileTime::NT_TIME_EPOCH - -time::Duration::ZERO,
1237            FileTime::NT_TIME_EPOCH
1238        );
1239        assert_eq!(
1240            FileTime::NT_TIME_EPOCH - -time::Duration::NANOSECOND,
1241            FileTime::NT_TIME_EPOCH
1242        );
1243        assert_eq!(
1244            FileTime::NT_TIME_EPOCH - -time::Duration::nanoseconds(99),
1245            FileTime::NT_TIME_EPOCH
1246        );
1247        assert_eq!(
1248            FileTime::NT_TIME_EPOCH - -time::Duration::nanoseconds(100),
1249            FileTime::new(1)
1250        );
1251
1252        assert_eq!(FileTime::MAX - -time::Duration::ZERO, FileTime::MAX);
1253        assert_eq!(FileTime::MAX - -time::Duration::NANOSECOND, FileTime::MAX);
1254        assert_eq!(
1255            FileTime::MAX - -time::Duration::nanoseconds(99),
1256            FileTime::MAX
1257        );
1258    }
1259
1260    #[test]
1261    #[should_panic(expected = "overflow when adding duration to date and time")]
1262    fn sub_negative_time_duration_with_overflow() {
1263        let _ = FileTime::MAX - -time::Duration::nanoseconds(100);
1264    }
1265
1266    #[cfg(feature = "chrono")]
1267    #[test]
1268    fn sub_positive_chrono_time_delta() {
1269        assert_eq!(FileTime::MAX - TimeDelta::zero(), FileTime::MAX);
1270        assert_eq!(FileTime::MAX - TimeDelta::nanoseconds(1), FileTime::MAX);
1271        assert_eq!(FileTime::MAX - TimeDelta::nanoseconds(99), FileTime::MAX);
1272        assert_eq!(
1273            FileTime::MAX - TimeDelta::nanoseconds(100),
1274            FileTime::new(u64::MAX - 1)
1275        );
1276
1277        assert_eq!(
1278            FileTime::NT_TIME_EPOCH - TimeDelta::zero(),
1279            FileTime::NT_TIME_EPOCH
1280        );
1281        assert_eq!(
1282            FileTime::NT_TIME_EPOCH - TimeDelta::nanoseconds(1),
1283            FileTime::NT_TIME_EPOCH
1284        );
1285        assert_eq!(
1286            FileTime::NT_TIME_EPOCH - TimeDelta::nanoseconds(99),
1287            FileTime::NT_TIME_EPOCH
1288        );
1289    }
1290
1291    #[cfg(feature = "chrono")]
1292    #[test]
1293    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1294    fn sub_positive_chrono_time_delta_with_overflow() {
1295        let _ = FileTime::NT_TIME_EPOCH - TimeDelta::nanoseconds(100);
1296    }
1297
1298    #[cfg(feature = "chrono")]
1299    #[test]
1300    fn sub_negative_chrono_time_delta() {
1301        assert_eq!(
1302            FileTime::NT_TIME_EPOCH - -TimeDelta::zero(),
1303            FileTime::NT_TIME_EPOCH
1304        );
1305        assert_eq!(
1306            FileTime::NT_TIME_EPOCH - -TimeDelta::nanoseconds(1),
1307            FileTime::NT_TIME_EPOCH
1308        );
1309        assert_eq!(
1310            FileTime::NT_TIME_EPOCH - -TimeDelta::nanoseconds(99),
1311            FileTime::NT_TIME_EPOCH
1312        );
1313        assert_eq!(
1314            FileTime::NT_TIME_EPOCH - -TimeDelta::nanoseconds(100),
1315            FileTime::new(1)
1316        );
1317
1318        assert_eq!(FileTime::MAX - -TimeDelta::zero(), FileTime::MAX);
1319        assert_eq!(FileTime::MAX - -TimeDelta::nanoseconds(1), FileTime::MAX);
1320        assert_eq!(FileTime::MAX - -TimeDelta::nanoseconds(99), FileTime::MAX);
1321    }
1322
1323    #[cfg(feature = "chrono")]
1324    #[test]
1325    #[should_panic(expected = "overflow when adding duration to date and time")]
1326    fn sub_negative_chrono_time_delta_with_overflow() {
1327        let _ = FileTime::MAX - -TimeDelta::nanoseconds(100);
1328    }
1329
1330    #[cfg(feature = "jiff")]
1331    #[test]
1332    fn sub_positive_jiff_span() {
1333        assert_eq!(FileTime::MAX - Span::new(), FileTime::MAX);
1334        assert_eq!(FileTime::MAX - 1.nanosecond(), FileTime::MAX);
1335        assert_eq!(FileTime::MAX - 99.nanoseconds(), FileTime::MAX);
1336        assert_eq!(
1337            FileTime::MAX - 100.nanoseconds(),
1338            FileTime::new(u64::MAX - 1)
1339        );
1340
1341        assert_eq!(
1342            FileTime::NT_TIME_EPOCH - Span::new(),
1343            FileTime::NT_TIME_EPOCH
1344        );
1345        assert_eq!(
1346            FileTime::NT_TIME_EPOCH - 1.nanosecond(),
1347            FileTime::NT_TIME_EPOCH
1348        );
1349        assert_eq!(
1350            FileTime::NT_TIME_EPOCH - 99.nanoseconds(),
1351            FileTime::NT_TIME_EPOCH
1352        );
1353    }
1354
1355    #[cfg(feature = "jiff")]
1356    #[test]
1357    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1358    fn sub_positive_jiff_span_with_overflow() {
1359        let _ = FileTime::NT_TIME_EPOCH - 100.nanoseconds();
1360    }
1361
1362    #[cfg(feature = "jiff")]
1363    #[test]
1364    fn sub_negative_jiff_span() {
1365        assert_eq!(
1366            FileTime::NT_TIME_EPOCH - -Span::new(),
1367            FileTime::NT_TIME_EPOCH
1368        );
1369        assert_eq!(
1370            FileTime::NT_TIME_EPOCH - -(1.nanosecond()),
1371            FileTime::NT_TIME_EPOCH
1372        );
1373        assert_eq!(
1374            FileTime::NT_TIME_EPOCH - -(99.nanoseconds()),
1375            FileTime::NT_TIME_EPOCH
1376        );
1377        assert_eq!(
1378            FileTime::NT_TIME_EPOCH - -(100.nanoseconds()),
1379            FileTime::new(1)
1380        );
1381
1382        assert_eq!(FileTime::MAX - -Span::new(), FileTime::MAX);
1383        assert_eq!(FileTime::MAX - -(1.nanosecond()), FileTime::MAX);
1384        assert_eq!(FileTime::MAX - -(99.nanoseconds()), FileTime::MAX);
1385    }
1386
1387    #[cfg(feature = "jiff")]
1388    #[test]
1389    #[should_panic(expected = "overflow when adding duration to date and time")]
1390    fn sub_negative_jiff_span_with_overflow() {
1391        let _ = FileTime::MAX - -(100.nanoseconds());
1392    }
1393
1394    #[cfg(feature = "std")]
1395    #[test]
1396    fn sub_file_time_from_system_time() {
1397        assert_eq!(
1398            (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700))
1399                - FileTime::new(9_223_372_036_854_775_807),
1400            Duration::ZERO
1401        );
1402        assert_eq!(
1403            (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700))
1404                - FileTime::new(9_223_372_036_854_775_806),
1405            Duration::from_nanos(100)
1406        );
1407        assert_eq!(
1408            (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700))
1409                - FileTime::UNIX_EPOCH,
1410            Duration::new(910_692_730_085, 477_580_700)
1411        );
1412    }
1413
1414    #[cfg(feature = "std")]
1415    #[test]
1416    #[should_panic(expected = "RHS provided is later than LHS")]
1417    fn sub_file_time_from_system_time_with_overflow() {
1418        let _ = FileTime::new(9_223_372_036_854_775_806)
1419            - (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700));
1420    }
1421
1422    #[cfg(feature = "std")]
1423    #[test]
1424    fn sub_system_time_from_file_time() {
1425        assert_eq!(
1426            FileTime::new(9_223_372_036_854_775_807)
1427                - (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_700)),
1428            Duration::ZERO
1429        );
1430        assert_eq!(
1431            FileTime::new(9_223_372_036_854_775_807)
1432                - (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_699)),
1433            Duration::from_nanos(if cfg!(windows) { 100 } else { 1 })
1434        );
1435        assert_eq!(
1436            FileTime::new(9_223_372_036_854_775_807)
1437                - (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_601)),
1438            Duration::from_nanos(if cfg!(windows) { 100 } else { 99 })
1439        );
1440        assert_eq!(
1441            FileTime::new(9_223_372_036_854_775_807)
1442                - (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_600)),
1443            Duration::from_nanos(100)
1444        );
1445        assert_eq!(
1446            FileTime::new(9_223_372_036_854_775_807) - SystemTime::UNIX_EPOCH,
1447            Duration::new(910_692_730_085, 477_580_700)
1448        );
1449    }
1450
1451    #[cfg(feature = "std")]
1452    #[test]
1453    #[should_panic(expected = "RHS provided is later than LHS")]
1454    fn sub_system_time_from_file_time_with_overflow() {
1455        let _ = (SystemTime::UNIX_EPOCH + Duration::new(910_692_730_085, 477_580_600))
1456            - FileTime::new(9_223_372_036_854_775_807);
1457    }
1458
1459    #[test]
1460    fn sub_file_time_from_utc_date_time() {
1461        assert_eq!(
1462            utc_datetime!(9999-12-31 23:59:59.999_999_900)
1463                - FileTime::new(2_650_467_743_999_999_999),
1464            time::Duration::ZERO
1465        );
1466        assert_eq!(
1467            utc_datetime!(9999-12-31 23:59:59.999_999_900)
1468                - (FileTime::new(2_650_467_743_999_999_999) - time::Duration::nanoseconds(100)),
1469            time::Duration::nanoseconds(100)
1470        );
1471        assert_eq!(
1472            utc_datetime!(9999-12-31 23:59:59.999_999_900) - FileTime::NT_TIME_EPOCH,
1473            time::Duration::new(265_046_774_399, 999_999_900)
1474        );
1475    }
1476
1477    #[test]
1478    fn sub_utc_date_time_from_file_time() {
1479        assert_eq!(
1480            FileTime::new(2_650_467_743_999_999_999)
1481                - utc_datetime!(9999-12-31 23:59:59.999_999_900),
1482            time::Duration::ZERO
1483        );
1484        assert_eq!(
1485            FileTime::new(2_650_467_743_999_999_999)
1486                - (utc_datetime!(9999-12-31 23:59:59.999_999_900) - time::Duration::nanoseconds(1)),
1487            time::Duration::nanoseconds(1)
1488        );
1489        assert_eq!(
1490            FileTime::new(2_650_467_743_999_999_999)
1491                - (utc_datetime!(9999-12-31 23:59:59.999_999_900)
1492                    - time::Duration::nanoseconds(99)),
1493            time::Duration::nanoseconds(99)
1494        );
1495        assert_eq!(
1496            FileTime::new(2_650_467_743_999_999_999)
1497                - (utc_datetime!(9999-12-31 23:59:59.999_999_900)
1498                    - time::Duration::nanoseconds(100)),
1499            time::Duration::nanoseconds(100)
1500        );
1501        assert_eq!(
1502            FileTime::new(2_650_467_743_999_999_999) - utc_datetime!(1601-01-01 00:00:00),
1503            time::Duration::new(265_046_774_399, 999_999_900)
1504        );
1505    }
1506
1507    #[cfg(feature = "chrono")]
1508    #[test]
1509    fn sub_file_time_from_chrono_date_time() {
1510        assert_eq!(
1511            "+60056-05-28 05:36:10.955161500 UTC"
1512                .parse::<DateTime<Utc>>()
1513                .unwrap()
1514                - FileTime::MAX,
1515            TimeDelta::zero()
1516        );
1517        assert_eq!(
1518            "+60056-05-28 05:36:10.955161500 UTC"
1519                .parse::<DateTime<Utc>>()
1520                .unwrap()
1521                - (FileTime::MAX - Duration::from_nanos(100)),
1522            TimeDelta::nanoseconds(100)
1523        );
1524        assert_eq!(
1525            "+60056-05-28 05:36:10.955161500 UTC"
1526                .parse::<DateTime<Utc>>()
1527                .unwrap()
1528                - FileTime::NT_TIME_EPOCH,
1529            TimeDelta::new(1_844_674_407_370, 955_161_500).unwrap()
1530        );
1531    }
1532
1533    #[cfg(feature = "chrono")]
1534    #[test]
1535    fn sub_chrono_date_time_from_file_time() {
1536        assert_eq!(
1537            FileTime::MAX
1538                - "+60056-05-28 05:36:10.955161500 UTC"
1539                    .parse::<DateTime<Utc>>()
1540                    .unwrap(),
1541            TimeDelta::zero()
1542        );
1543        assert_eq!(
1544            FileTime::MAX
1545                - ("+60056-05-28 05:36:10.955161500 UTC"
1546                    .parse::<DateTime<Utc>>()
1547                    .unwrap()
1548                    - TimeDelta::nanoseconds(1)),
1549            TimeDelta::nanoseconds(1)
1550        );
1551        assert_eq!(
1552            FileTime::MAX
1553                - ("+60056-05-28 05:36:10.955161500 UTC"
1554                    .parse::<DateTime<Utc>>()
1555                    .unwrap()
1556                    - TimeDelta::nanoseconds(99)),
1557            TimeDelta::nanoseconds(99)
1558        );
1559        assert_eq!(
1560            FileTime::MAX
1561                - ("+60056-05-28 05:36:10.955161500 UTC"
1562                    .parse::<DateTime<Utc>>()
1563                    .unwrap()
1564                    - TimeDelta::nanoseconds(100)),
1565            TimeDelta::nanoseconds(100)
1566        );
1567        assert_eq!(
1568            FileTime::MAX - "1601-01-01 00:00:00 UTC".parse::<DateTime<Utc>>().unwrap(),
1569            TimeDelta::new(1_844_674_407_370, 955_161_500).unwrap()
1570        );
1571    }
1572
1573    #[cfg(feature = "jiff")]
1574    #[test]
1575    fn sub_file_time_from_jiff_timestamp() {
1576        assert_eq!(
1577            (Timestamp::MAX - 99.nanoseconds()) - FileTime::new(2_650_466_808_009_999_999),
1578            Span::new().fieldwise()
1579        );
1580        assert_eq!(
1581            (Timestamp::MAX - 99.nanoseconds())
1582                - (FileTime::new(2_650_466_808_009_999_999) - 100.nanoseconds()),
1583            100.nanoseconds().fieldwise()
1584        );
1585        assert_eq!(
1586            (Timestamp::MAX - 99.nanoseconds()) - FileTime::NT_TIME_EPOCH,
1587            265_046_680_800_i64
1588                .seconds()
1589                .milliseconds(999)
1590                .microseconds(999)
1591                .nanoseconds(900)
1592                .fieldwise()
1593        );
1594    }
1595
1596    #[cfg(feature = "jiff")]
1597    #[test]
1598    fn sub_jiff_timestamp_from_file_time() {
1599        assert_eq!(
1600            FileTime::new(2_650_466_808_009_999_999) - (Timestamp::MAX - 99.nanoseconds()),
1601            Span::new().fieldwise()
1602        );
1603        assert_eq!(
1604            FileTime::new(2_650_466_808_009_999_999)
1605                - ((Timestamp::MAX - 99.nanoseconds()) - 1.nanosecond()),
1606            1.nanosecond().fieldwise()
1607        );
1608        assert_eq!(
1609            FileTime::new(2_650_466_808_009_999_999)
1610                - ((Timestamp::MAX - 99.nanoseconds()) - 99.nanoseconds()),
1611            99.nanoseconds().fieldwise()
1612        );
1613        assert_eq!(
1614            FileTime::new(2_650_466_808_009_999_999)
1615                - ((Timestamp::MAX - 99.nanoseconds()) - 100.nanoseconds()),
1616            100.nanoseconds().fieldwise()
1617        );
1618        assert_eq!(
1619            FileTime::new(2_650_466_808_009_999_999)
1620                - Timestamp::from_second(-11_644_473_600).unwrap(),
1621            265_046_680_800_i64
1622                .seconds()
1623                .milliseconds(999)
1624                .microseconds(999)
1625                .nanoseconds(900)
1626                .fieldwise()
1627        );
1628    }
1629
1630    #[test]
1631    fn sub_assign_std_duration() {
1632        {
1633            let mut ft = FileTime::MAX;
1634            ft -= Duration::ZERO;
1635            assert_eq!(ft, FileTime::MAX);
1636        }
1637        {
1638            let mut ft = FileTime::MAX;
1639            ft -= Duration::from_nanos(1);
1640            assert_eq!(ft, FileTime::MAX);
1641        }
1642        {
1643            let mut ft = FileTime::MAX;
1644            ft -= Duration::from_nanos(99);
1645            assert_eq!(ft, FileTime::MAX);
1646        }
1647        {
1648            let mut ft = FileTime::MAX;
1649            ft -= Duration::from_nanos(100);
1650            assert_eq!(ft, FileTime::new(u64::MAX - 1));
1651        }
1652
1653        {
1654            let mut ft = FileTime::NT_TIME_EPOCH;
1655            ft -= Duration::ZERO;
1656            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1657        }
1658        {
1659            let mut ft = FileTime::NT_TIME_EPOCH;
1660            ft -= Duration::from_nanos(1);
1661            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1662        }
1663        {
1664            let mut ft = FileTime::NT_TIME_EPOCH;
1665            ft -= Duration::from_nanos(99);
1666            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1667        }
1668    }
1669
1670    #[test]
1671    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1672    fn sub_assign_std_duration_with_overflow() {
1673        let mut ft = FileTime::NT_TIME_EPOCH;
1674        ft -= Duration::from_nanos(100);
1675    }
1676
1677    #[test]
1678    fn sub_assign_positive_time_duration() {
1679        {
1680            let mut ft = FileTime::MAX;
1681            ft -= time::Duration::ZERO;
1682            assert_eq!(ft, FileTime::MAX);
1683        }
1684        {
1685            let mut ft = FileTime::MAX;
1686            ft -= time::Duration::NANOSECOND;
1687            assert_eq!(ft, FileTime::MAX);
1688        }
1689        {
1690            let mut ft = FileTime::MAX;
1691            ft -= time::Duration::nanoseconds(99);
1692            assert_eq!(ft, FileTime::MAX);
1693        }
1694        {
1695            let mut ft = FileTime::MAX;
1696            ft -= time::Duration::nanoseconds(100);
1697            assert_eq!(ft, FileTime::new(u64::MAX - 1));
1698        }
1699
1700        {
1701            let mut ft = FileTime::NT_TIME_EPOCH;
1702            ft -= time::Duration::ZERO;
1703            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1704        }
1705        {
1706            let mut ft = FileTime::NT_TIME_EPOCH;
1707            ft -= time::Duration::NANOSECOND;
1708            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1709        }
1710        {
1711            let mut ft = FileTime::NT_TIME_EPOCH;
1712            ft -= time::Duration::nanoseconds(99);
1713            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1714        }
1715    }
1716
1717    #[test]
1718    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1719    fn sub_assign_positive_time_duration_with_overflow() {
1720        let mut ft = FileTime::NT_TIME_EPOCH;
1721        ft -= time::Duration::nanoseconds(100);
1722    }
1723
1724    #[test]
1725    fn sub_assign_negative_time_duration() {
1726        {
1727            let mut ft = FileTime::NT_TIME_EPOCH;
1728            ft -= -time::Duration::ZERO;
1729            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1730        }
1731        {
1732            let mut ft = FileTime::NT_TIME_EPOCH;
1733            ft -= -time::Duration::NANOSECOND;
1734            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1735        }
1736        {
1737            let mut ft = FileTime::NT_TIME_EPOCH;
1738            ft -= -time::Duration::nanoseconds(99);
1739            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1740        }
1741        {
1742            let mut ft = FileTime::NT_TIME_EPOCH;
1743            ft -= -time::Duration::nanoseconds(100);
1744            assert_eq!(ft, FileTime::new(1));
1745        }
1746
1747        {
1748            let mut ft = FileTime::MAX;
1749            ft -= -time::Duration::ZERO;
1750            assert_eq!(ft, FileTime::MAX);
1751        }
1752        {
1753            let mut ft = FileTime::MAX;
1754            ft -= -time::Duration::NANOSECOND;
1755            assert_eq!(ft, FileTime::MAX);
1756        }
1757        {
1758            let mut ft = FileTime::MAX;
1759            ft -= -time::Duration::nanoseconds(99);
1760            assert_eq!(ft, FileTime::MAX);
1761        }
1762    }
1763
1764    #[test]
1765    #[should_panic(expected = "overflow when adding duration to date and time")]
1766    fn sub_assign_negative_time_duration_with_overflow() {
1767        let mut ft = FileTime::MAX;
1768        ft -= -time::Duration::nanoseconds(100);
1769    }
1770
1771    #[cfg(feature = "chrono")]
1772    #[test]
1773    fn sub_assign_positive_chrono_time_delta() {
1774        {
1775            let mut ft = FileTime::MAX;
1776            ft -= TimeDelta::zero();
1777            assert_eq!(ft, FileTime::MAX);
1778        }
1779        {
1780            let mut ft = FileTime::MAX;
1781            ft -= TimeDelta::nanoseconds(1);
1782            assert_eq!(ft, FileTime::MAX);
1783        }
1784        {
1785            let mut ft = FileTime::MAX;
1786            ft -= TimeDelta::nanoseconds(99);
1787            assert_eq!(ft, FileTime::MAX);
1788        }
1789        {
1790            let mut ft = FileTime::MAX;
1791            ft -= TimeDelta::nanoseconds(100);
1792            assert_eq!(ft, FileTime::new(u64::MAX - 1));
1793        }
1794
1795        {
1796            let mut ft = FileTime::NT_TIME_EPOCH;
1797            ft -= TimeDelta::zero();
1798            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1799        }
1800        {
1801            let mut ft = FileTime::NT_TIME_EPOCH;
1802            ft -= TimeDelta::nanoseconds(1);
1803            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1804        }
1805        {
1806            let mut ft = FileTime::NT_TIME_EPOCH;
1807            ft -= TimeDelta::nanoseconds(99);
1808            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1809        }
1810    }
1811
1812    #[cfg(feature = "chrono")]
1813    #[test]
1814    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1815    fn sub_assign_positive_chrono_time_delta_with_overflow() {
1816        let mut ft = FileTime::NT_TIME_EPOCH;
1817        ft -= TimeDelta::nanoseconds(100);
1818    }
1819
1820    #[cfg(feature = "chrono")]
1821    #[test]
1822    fn sub_assign_negative_chrono_time_delta() {
1823        {
1824            let mut ft = FileTime::NT_TIME_EPOCH;
1825            ft -= -TimeDelta::zero();
1826            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1827        }
1828        {
1829            let mut ft = FileTime::NT_TIME_EPOCH;
1830            ft -= -TimeDelta::nanoseconds(1);
1831            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1832        }
1833        {
1834            let mut ft = FileTime::NT_TIME_EPOCH;
1835            ft -= -TimeDelta::nanoseconds(99);
1836            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1837        }
1838        {
1839            let mut ft = FileTime::NT_TIME_EPOCH;
1840            ft -= -TimeDelta::nanoseconds(100);
1841            assert_eq!(ft, FileTime::new(1));
1842        }
1843
1844        {
1845            let mut ft = FileTime::MAX;
1846            ft -= -TimeDelta::zero();
1847            assert_eq!(ft, FileTime::MAX);
1848        }
1849        {
1850            let mut ft = FileTime::MAX;
1851            ft -= -TimeDelta::nanoseconds(1);
1852            assert_eq!(ft, FileTime::MAX);
1853        }
1854        {
1855            let mut ft = FileTime::MAX;
1856            ft -= -TimeDelta::nanoseconds(99);
1857            assert_eq!(ft, FileTime::MAX);
1858        }
1859    }
1860
1861    #[cfg(feature = "chrono")]
1862    #[test]
1863    #[should_panic(expected = "overflow when adding duration to date and time")]
1864    fn sub_assign_negative_chrono_time_delta_with_overflow() {
1865        let mut ft = FileTime::MAX;
1866        ft -= -TimeDelta::nanoseconds(100);
1867    }
1868
1869    #[cfg(feature = "jiff")]
1870    #[test]
1871    fn sub_assign_positive_jiff_span() {
1872        {
1873            let mut ft = FileTime::MAX;
1874            ft -= Span::new();
1875            assert_eq!(ft, FileTime::MAX);
1876        }
1877        {
1878            let mut ft = FileTime::MAX;
1879            ft -= 1.nanosecond();
1880            assert_eq!(ft, FileTime::MAX);
1881        }
1882        {
1883            let mut ft = FileTime::MAX;
1884            ft -= 99.nanoseconds();
1885            assert_eq!(ft, FileTime::MAX);
1886        }
1887        {
1888            let mut ft = FileTime::MAX;
1889            ft -= 100.nanoseconds();
1890            assert_eq!(ft, FileTime::new(u64::MAX - 1));
1891        }
1892
1893        {
1894            let mut ft = FileTime::NT_TIME_EPOCH;
1895            ft -= Span::new();
1896            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1897        }
1898        {
1899            let mut ft = FileTime::NT_TIME_EPOCH;
1900            ft -= 1.nanosecond();
1901            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1902        }
1903        {
1904            let mut ft = FileTime::NT_TIME_EPOCH;
1905            ft -= 99.nanoseconds();
1906            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1907        }
1908    }
1909
1910    #[cfg(feature = "jiff")]
1911    #[test]
1912    #[should_panic(expected = "overflow when subtracting duration from date and time")]
1913    fn sub_assign_positive_jiff_span_with_overflow() {
1914        let mut ft = FileTime::NT_TIME_EPOCH;
1915        ft -= 100.nanoseconds();
1916    }
1917
1918    #[cfg(feature = "jiff")]
1919    #[test]
1920    fn sub_assign_negative_jiff_span() {
1921        {
1922            let mut ft = FileTime::NT_TIME_EPOCH;
1923            ft -= -Span::new();
1924            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1925        }
1926        {
1927            let mut ft = FileTime::NT_TIME_EPOCH;
1928            ft -= -(1.nanosecond());
1929            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1930        }
1931        {
1932            let mut ft = FileTime::NT_TIME_EPOCH;
1933            ft -= -(99.nanoseconds());
1934            assert_eq!(ft, FileTime::NT_TIME_EPOCH);
1935        }
1936        {
1937            let mut ft = FileTime::NT_TIME_EPOCH;
1938            ft -= -(100.nanoseconds());
1939            assert_eq!(ft, FileTime::new(1));
1940        }
1941
1942        {
1943            let mut ft = FileTime::MAX;
1944            ft -= -Span::new();
1945            assert_eq!(ft, FileTime::MAX);
1946        }
1947        {
1948            let mut ft = FileTime::MAX;
1949            ft -= -(1.nanosecond());
1950            assert_eq!(ft, FileTime::MAX);
1951        }
1952        {
1953            let mut ft = FileTime::MAX;
1954            ft -= -(99.nanoseconds());
1955            assert_eq!(ft, FileTime::MAX);
1956        }
1957    }
1958
1959    #[cfg(feature = "jiff")]
1960    #[test]
1961    #[should_panic(expected = "overflow when adding duration to date and time")]
1962    fn sub_assign_negative_jiff_span_with_overflow() {
1963        let mut ft = FileTime::MAX;
1964        ft -= -(100.nanoseconds());
1965    }
1966}