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