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