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