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