1use core::time::Duration;
10
11use super::{FILE_TIMES_PER_SEC, FileTime};
12use crate::error::{FileTimeRangeError, FileTimeRangeErrorKind};
13
14impl FileTime {
15 #[expect(clippy::missing_panics_doc)]
16 #[must_use]
44 pub fn to_unix_time(self) -> (i64, u32) {
45 let (secs, subsec_nanos) = (
46 self.to_unix_time_secs(),
47 u32::try_from((self.to_raw() % FILE_TIMES_PER_SEC) * 100)
48 .expect("the number of nanoseconds should be in the range of `u32`"),
49 );
50 (secs, subsec_nanos)
51 }
52
53 #[expect(clippy::missing_panics_doc)]
54 #[must_use]
70 pub fn to_unix_time_secs(self) -> i64 {
71 i64::try_from(self.to_raw() / FILE_TIMES_PER_SEC)
72 .expect("the number of seconds should be in the range of `i64`")
73 - 11_644_473_600
74 }
75
76 #[expect(clippy::missing_panics_doc)]
77 #[must_use]
99 pub fn to_unix_time_millis(self) -> i64 {
100 self.to_unix_time_nanos()
101 .div_euclid(1_000_000)
102 .try_into()
103 .expect("the number of milliseconds should be in the range of `i64`")
104 }
105
106 #[expect(clippy::missing_panics_doc)]
107 #[must_use]
132 pub fn to_unix_time_micros(self) -> i64 {
133 self.to_unix_time_nanos()
134 .div_euclid(1000)
135 .try_into()
136 .expect("the number of microseconds should be in the range of `i64`")
137 }
138
139 #[must_use]
164 pub fn to_unix_time_nanos(self) -> i128 {
165 (i128::from(self.to_raw()) * 100) - 11_644_473_600_000_000_000
166 }
167
168 pub fn from_unix_time(secs: i64, nanos: u32) -> Result<Self, FileTimeRangeError> {
220 Self::from_unix_time_secs(secs)?
221 .checked_add(Duration::from_nanos(nanos.into()))
222 .ok_or_else(|| FileTimeRangeErrorKind::Overflow.into())
223 }
224
225 pub fn from_unix_time_secs(secs: i64) -> Result<Self, FileTimeRangeError> {
260 if secs <= 1_833_029_933_770 {
261 let duration = u64::try_from(secs + 11_644_473_600)
262 .map_err(|_| FileTimeRangeErrorKind::Negative)?;
263 Ok(Self::new(duration * FILE_TIMES_PER_SEC))
264 } else {
265 Err(FileTimeRangeErrorKind::Overflow.into())
266 }
267 }
268
269 pub fn from_unix_time_millis(millis: i64) -> Result<Self, FileTimeRangeError> {
304 let nanos = i128::from(millis) * 1_000_000;
305 Self::from_unix_time_nanos(nanos)
306 }
307
308 pub fn from_unix_time_micros(micros: i64) -> Result<Self, FileTimeRangeError> {
343 let nanos = i128::from(micros) * 1000;
344 Self::from_unix_time_nanos(nanos)
345 }
346
347 pub fn from_unix_time_nanos(nanos: i128) -> Result<Self, FileTimeRangeError> {
380 if nanos <= 1_833_029_933_770_955_161_500 {
381 let ft = (nanos + 11_644_473_600_000_000_000)
382 .div_euclid(100)
383 .try_into()
384 .map_err(|_| FileTimeRangeErrorKind::Negative)?;
385 Ok(Self::new(ft))
386 } else {
387 Err(FileTimeRangeErrorKind::Overflow.into())
388 }
389 }
390}
391
392#[cfg(test)]
393mod tests {
394 #[cfg(feature = "std")]
395 use proptest::{prop_assert, prop_assert_eq, prop_assume};
396 #[cfg(feature = "std")]
397 use test_strategy::proptest;
398
399 use super::*;
400
401 const NANOS_PER_SEC: u32 = 1_000_000_000;
402
403 #[test]
404 fn to_unix_time() {
405 assert_eq!(
406 FileTime::NT_TIME_EPOCH.to_unix_time(),
407 (-11_644_473_600, u32::MIN)
408 );
409 assert_eq!(FileTime::new(1).to_unix_time(), (-11_644_473_600, 100));
410 assert_eq!(
411 FileTime::new(FILE_TIMES_PER_SEC - 1).to_unix_time(),
412 (-11_644_473_600, NANOS_PER_SEC - 100)
413 );
414 assert_eq!(
415 FileTime::new(FILE_TIMES_PER_SEC).to_unix_time(),
416 (-11_644_473_599, u32::MIN)
417 );
418 assert_eq!(
419 (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time(),
420 (i64::default() - 1, NANOS_PER_SEC - 100)
421 );
422 assert_eq!(
423 FileTime::UNIX_EPOCH.to_unix_time(),
424 (i64::default(), u32::MIN)
425 );
426 assert_eq!(
427 (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time(),
428 (i64::default(), 100)
429 );
430 assert_eq!(
431 FileTime::SIGNED_MAX.to_unix_time(),
432 (910_692_730_085, 477_580_700)
433 );
434 assert_eq!(
435 (FileTime::MAX - Duration::from_nanos(100)).to_unix_time(),
436 (1_833_029_933_770, 955_161_400)
437 );
438 assert_eq!(
439 FileTime::MAX.to_unix_time(),
440 (1_833_029_933_770, 955_161_500)
441 );
442 }
443
444 #[cfg(feature = "std")]
445 #[proptest]
446 fn to_unix_time_roundtrip(ft: FileTime) {
447 let ts = ft.to_unix_time();
448 prop_assert!((-11_644_473_600..=1_833_029_933_770).contains(&ts.0));
449 prop_assert!(ts.1 < NANOS_PER_SEC);
450 }
451
452 #[test]
453 fn to_unix_time_secs() {
454 assert_eq!(FileTime::NT_TIME_EPOCH.to_unix_time_secs(), -11_644_473_600);
455 assert_eq!(FileTime::new(1).to_unix_time_secs(), -11_644_473_600);
456 assert_eq!(
457 FileTime::new(FILE_TIMES_PER_SEC - 1).to_unix_time_secs(),
458 -11_644_473_600
459 );
460 assert_eq!(
461 FileTime::new(FILE_TIMES_PER_SEC).to_unix_time_secs(),
462 -11_644_473_599
463 );
464 assert_eq!(
465 (FileTime::UNIX_EPOCH - Duration::from_secs(1)).to_unix_time_secs(),
466 i64::default() - 1
467 );
468 assert_eq!(
469 (FileTime::UNIX_EPOCH - Duration::from_nanos(999_999_900)).to_unix_time_secs(),
470 i64::default() - 1
471 );
472 assert_eq!(
473 (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time_secs(),
474 i64::default() - 1
475 );
476 assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_secs(), i64::default());
477 assert_eq!(
478 (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time_secs(),
479 i64::default()
480 );
481 assert_eq!(
482 (FileTime::UNIX_EPOCH + Duration::from_nanos(999_999_900)).to_unix_time_secs(),
483 i64::default()
484 );
485 assert_eq!(
486 (FileTime::UNIX_EPOCH + Duration::from_secs(1)).to_unix_time_secs(),
487 i64::default() + 1
488 );
489 assert_eq!(FileTime::SIGNED_MAX.to_unix_time_secs(), 910_692_730_085);
490 assert_eq!(
491 (FileTime::MAX - Duration::from_nanos(955_161_600)).to_unix_time_secs(),
492 1_833_029_933_769
493 );
494 assert_eq!(
495 (FileTime::MAX - Duration::from_nanos(955_161_500)).to_unix_time_secs(),
496 1_833_029_933_770
497 );
498 assert_eq!(
499 (FileTime::MAX - Duration::from_nanos(955_161_400)).to_unix_time_secs(),
500 1_833_029_933_770
501 );
502 assert_eq!(FileTime::MAX.to_unix_time_secs(), 1_833_029_933_770);
503 }
504
505 #[cfg(feature = "std")]
506 #[proptest]
507 fn to_unix_time_secs_roundtrip(ft: FileTime) {
508 let ts = ft.to_unix_time_secs();
509 prop_assert!((-11_644_473_600..=1_833_029_933_770).contains(&ts));
510 }
511
512 #[test]
513 fn to_unix_time_millis() {
514 assert_eq!(
515 FileTime::NT_TIME_EPOCH.to_unix_time_millis(),
516 -11_644_473_600_000
517 );
518 assert_eq!(FileTime::new(1).to_unix_time_millis(), -11_644_473_600_000);
519 assert_eq!(
520 FileTime::new(9999).to_unix_time_millis(),
521 -11_644_473_600_000
522 );
523 assert_eq!(
524 FileTime::new(10000).to_unix_time_millis(),
525 -11_644_473_599_999
526 );
527 assert_eq!(
528 (FileTime::UNIX_EPOCH - Duration::from_millis(1)).to_unix_time_millis(),
529 i64::default() - 1
530 );
531 assert_eq!(
532 (FileTime::UNIX_EPOCH - Duration::from_nanos(999_900)).to_unix_time_millis(),
533 i64::default() - 1
534 );
535 assert_eq!(
536 (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time_millis(),
537 i64::default() - 1
538 );
539 assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_millis(), i64::default());
540 assert_eq!(
541 (FileTime::UNIX_EPOCH + Duration::from_nanos(999_900)).to_unix_time_millis(),
542 i64::default()
543 );
544 assert_eq!(
545 (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time_millis(),
546 i64::default()
547 );
548 assert_eq!(
549 (FileTime::UNIX_EPOCH + Duration::from_millis(1)).to_unix_time_millis(),
550 i64::default() + 1
551 );
552 assert_eq!(
553 FileTime::SIGNED_MAX.to_unix_time_millis(),
554 910_692_730_085_477
555 );
556 assert_eq!(
557 (FileTime::MAX - Duration::from_nanos(161_600)).to_unix_time_millis(),
558 1_833_029_933_770_954
559 );
560 assert_eq!(
561 (FileTime::MAX - Duration::from_nanos(161_500)).to_unix_time_millis(),
562 1_833_029_933_770_955
563 );
564 assert_eq!(
565 (FileTime::MAX - Duration::from_nanos(161_400)).to_unix_time_millis(),
566 1_833_029_933_770_955
567 );
568 assert_eq!(FileTime::MAX.to_unix_time_millis(), 1_833_029_933_770_955);
569 }
570
571 #[cfg(feature = "std")]
572 #[proptest]
573 fn to_unix_time_millis_roundtrip(ft: FileTime) {
574 let ts = ft.to_unix_time_millis();
575 prop_assert!((-11_644_473_600_000..=1_833_029_933_770_955).contains(&ts));
576 }
577
578 #[test]
579 fn to_unix_time_micros() {
580 assert_eq!(
581 FileTime::NT_TIME_EPOCH.to_unix_time_micros(),
582 -11_644_473_600_000_000
583 );
584 assert_eq!(
585 FileTime::new(1).to_unix_time_micros(),
586 -11_644_473_600_000_000
587 );
588 assert_eq!(
589 FileTime::new(9).to_unix_time_micros(),
590 -11_644_473_600_000_000
591 );
592 assert_eq!(
593 FileTime::new(10).to_unix_time_micros(),
594 -11_644_473_599_999_999
595 );
596 assert_eq!(
597 (FileTime::UNIX_EPOCH - Duration::from_micros(1)).to_unix_time_micros(),
598 i64::default() - 1
599 );
600 assert_eq!(
601 (FileTime::UNIX_EPOCH - Duration::from_nanos(900)).to_unix_time_micros(),
602 i64::default() - 1
603 );
604 assert_eq!(
605 (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time_micros(),
606 i64::default() - 1
607 );
608 assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_micros(), i64::default());
609 assert_eq!(
610 (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time_micros(),
611 i64::default()
612 );
613 assert_eq!(
614 (FileTime::UNIX_EPOCH + Duration::from_nanos(900)).to_unix_time_micros(),
615 i64::default()
616 );
617 assert_eq!(
618 (FileTime::UNIX_EPOCH + Duration::from_micros(1)).to_unix_time_micros(),
619 i64::default() + 1
620 );
621 assert_eq!(
622 FileTime::SIGNED_MAX.to_unix_time_micros(),
623 910_692_730_085_477_580
624 );
625 assert_eq!(
626 (FileTime::MAX - Duration::from_nanos(600)).to_unix_time_micros(),
627 1_833_029_933_770_955_160
628 );
629 assert_eq!(
630 (FileTime::MAX - Duration::from_nanos(500)).to_unix_time_micros(),
631 1_833_029_933_770_955_161
632 );
633 assert_eq!(
634 (FileTime::MAX - Duration::from_nanos(400)).to_unix_time_micros(),
635 1_833_029_933_770_955_161
636 );
637 assert_eq!(
638 FileTime::MAX.to_unix_time_micros(),
639 1_833_029_933_770_955_161
640 );
641 }
642
643 #[cfg(feature = "std")]
644 #[proptest]
645 fn to_unix_time_micros_roundtrip(ft: FileTime) {
646 let ts = ft.to_unix_time_micros();
647 prop_assert!((-11_644_473_600_000_000..=1_833_029_933_770_955_161).contains(&ts));
648 }
649
650 #[test]
651 fn to_unix_time_nanos() {
652 assert_eq!(
653 FileTime::NT_TIME_EPOCH.to_unix_time_nanos(),
654 -11_644_473_600_000_000_000
655 );
656 assert_eq!(
657 FileTime::new(1).to_unix_time_nanos(),
658 -11_644_473_599_999_999_900
659 );
660 assert_eq!(
661 FileTime::new(FILE_TIMES_PER_SEC - 1).to_unix_time_nanos(),
662 -11_644_473_599_000_000_100
663 );
664 assert_eq!(
665 FileTime::new(FILE_TIMES_PER_SEC).to_unix_time_nanos(),
666 -11_644_473_599_000_000_000
667 );
668 assert_eq!(
669 (FileTime::UNIX_EPOCH - Duration::from_nanos(100)).to_unix_time_nanos(),
670 i128::default() - 100
671 );
672 assert_eq!(FileTime::UNIX_EPOCH.to_unix_time_nanos(), i128::default());
673 assert_eq!(
674 (FileTime::UNIX_EPOCH + Duration::from_nanos(100)).to_unix_time_nanos(),
675 i128::default() + 100
676 );
677 assert_eq!(
678 FileTime::SIGNED_MAX.to_unix_time_nanos(),
679 910_692_730_085_477_580_700
680 );
681 assert_eq!(
682 (FileTime::MAX - Duration::from_nanos(100)).to_unix_time_nanos(),
683 1_833_029_933_770_955_161_400
684 );
685 assert_eq!(
686 FileTime::MAX.to_unix_time_nanos(),
687 1_833_029_933_770_955_161_500
688 );
689 }
690
691 #[cfg(feature = "std")]
692 #[proptest]
693 fn to_unix_time_nanos_roundtrip(ft: FileTime) {
694 let ts = ft.to_unix_time_nanos();
695 prop_assert!((-11_644_473_600_000_000_000..=1_833_029_933_770_955_161_500).contains(&ts));
696 }
697
698 #[test]
699 fn from_unix_time_before_nt_time_epoch() {
700 assert_eq!(
701 FileTime::from_unix_time(-11_644_473_601, u32::MAX).unwrap_err(),
702 FileTimeRangeErrorKind::Negative.into()
703 );
704 assert_eq!(
705 FileTime::from_unix_time(-11_644_473_601, NANOS_PER_SEC).unwrap_err(),
706 FileTimeRangeErrorKind::Negative.into()
707 );
708 assert_eq!(
709 FileTime::from_unix_time(-11_644_473_601, NANOS_PER_SEC - 1).unwrap_err(),
710 FileTimeRangeErrorKind::Negative.into()
711 );
712 assert_eq!(
713 FileTime::from_unix_time(-11_644_473_601, NANOS_PER_SEC - 99).unwrap_err(),
714 FileTimeRangeErrorKind::Negative.into()
715 );
716 assert_eq!(
717 FileTime::from_unix_time(-11_644_473_601, NANOS_PER_SEC - 100).unwrap_err(),
718 FileTimeRangeErrorKind::Negative.into()
719 );
720 assert_eq!(
721 FileTime::from_unix_time(-11_644_473_601, u32::MIN).unwrap_err(),
722 FileTimeRangeErrorKind::Negative.into()
723 );
724 assert_eq!(
725 FileTime::from_unix_time(i64::MIN, u32::MAX).unwrap_err(),
726 FileTimeRangeErrorKind::Negative.into()
727 );
728 assert_eq!(
729 FileTime::from_unix_time(i64::MIN, NANOS_PER_SEC).unwrap_err(),
730 FileTimeRangeErrorKind::Negative.into()
731 );
732 assert_eq!(
733 FileTime::from_unix_time(i64::MIN, NANOS_PER_SEC - 1).unwrap_err(),
734 FileTimeRangeErrorKind::Negative.into()
735 );
736 assert_eq!(
737 FileTime::from_unix_time(i64::MIN, u32::MIN).unwrap_err(),
738 FileTimeRangeErrorKind::Negative.into()
739 );
740 }
741
742 #[cfg(feature = "std")]
743 #[proptest]
744 fn from_unix_time_before_nt_time_epoch_roundtrip(
745 #[strategy(..=-11_644_473_601_i64)] secs: i64,
746 nanos: u32,
747 ) {
748 prop_assert_eq!(
749 FileTime::from_unix_time(secs, nanos).unwrap_err(),
750 FileTimeRangeErrorKind::Negative.into()
751 );
752 }
753
754 #[test]
755 fn from_unix_time() {
756 assert_eq!(
757 FileTime::from_unix_time(-11_644_473_600, 0).unwrap(),
758 FileTime::NT_TIME_EPOCH
759 );
760 assert_eq!(
761 FileTime::from_unix_time(-11_644_473_600, 1).unwrap(),
762 FileTime::NT_TIME_EPOCH
763 );
764 assert_eq!(
765 FileTime::from_unix_time(-11_644_473_600, 99).unwrap(),
766 FileTime::NT_TIME_EPOCH
767 );
768 assert_eq!(
769 FileTime::from_unix_time(-11_644_473_600, 100).unwrap(),
770 FileTime::new(1)
771 );
772 assert_eq!(
773 FileTime::from_unix_time(-11_644_473_600, NANOS_PER_SEC - 100).unwrap(),
774 FileTime::new(FILE_TIMES_PER_SEC - 1)
775 );
776 assert_eq!(
777 FileTime::from_unix_time(-11_644_473_600, NANOS_PER_SEC - 99).unwrap(),
778 FileTime::new(FILE_TIMES_PER_SEC - 1)
779 );
780 assert_eq!(
781 FileTime::from_unix_time(-11_644_473_600, NANOS_PER_SEC - 1).unwrap(),
782 FileTime::new(FILE_TIMES_PER_SEC - 1)
783 );
784 assert_eq!(
785 FileTime::from_unix_time(-11_644_473_600, NANOS_PER_SEC).unwrap(),
786 FileTime::new(FILE_TIMES_PER_SEC)
787 );
788 assert_eq!(
789 FileTime::from_unix_time(-11_644_473_599, 0).unwrap(),
790 FileTime::new(FILE_TIMES_PER_SEC)
791 );
792 assert_eq!(
793 FileTime::from_unix_time(i64::default() - 1, NANOS_PER_SEC - 100).unwrap(),
794 FileTime::UNIX_EPOCH - Duration::from_nanos(100)
795 );
796 assert_eq!(
797 FileTime::from_unix_time(i64::default() - 1, NANOS_PER_SEC - 99).unwrap(),
798 FileTime::UNIX_EPOCH - Duration::from_nanos(100)
799 );
800 assert_eq!(
801 FileTime::from_unix_time(i64::default() - 1, NANOS_PER_SEC - 1).unwrap(),
802 FileTime::UNIX_EPOCH - Duration::from_nanos(100)
803 );
804 assert_eq!(
805 FileTime::from_unix_time(i64::default() - 1, NANOS_PER_SEC).unwrap(),
806 FileTime::UNIX_EPOCH
807 );
808 assert_eq!(
809 FileTime::from_unix_time(i64::default(), u32::MIN).unwrap(),
810 FileTime::UNIX_EPOCH
811 );
812 assert_eq!(
813 FileTime::from_unix_time(i64::default(), 1).unwrap(),
814 FileTime::UNIX_EPOCH
815 );
816 assert_eq!(
817 FileTime::from_unix_time(i64::default(), 99).unwrap(),
818 FileTime::UNIX_EPOCH
819 );
820 assert_eq!(
821 FileTime::from_unix_time(i64::default(), 100).unwrap(),
822 FileTime::UNIX_EPOCH + Duration::from_nanos(100)
823 );
824 assert_eq!(
825 FileTime::from_unix_time(910_692_730_085, 477_580_700).unwrap(),
826 FileTime::SIGNED_MAX
827 );
828 assert_eq!(
829 FileTime::from_unix_time(1_833_029_933_770, 955_161_500).unwrap(),
830 FileTime::MAX
831 );
832 assert_eq!(
833 FileTime::from_unix_time(1_833_029_933_770, 955_161_501).unwrap(),
834 FileTime::MAX
835 );
836 assert_eq!(
837 FileTime::from_unix_time(1_833_029_933_770, 955_161_599).unwrap(),
838 FileTime::MAX
839 );
840 }
841
842 #[cfg(feature = "std")]
843 #[proptest]
844 fn from_unix_time_roundtrip(
845 #[strategy(-11_644_473_600..=1_833_029_933_770_i64)] secs: i64,
846 #[strategy(..NANOS_PER_SEC)] nanos: u32,
847 ) {
848 if secs == 1_833_029_933_770 {
849 prop_assume!(nanos < 955_161_600);
850 }
851
852 prop_assert!(FileTime::from_unix_time(secs, nanos).is_ok());
853 }
854
855 #[test]
856 fn from_unix_time_with_too_big_date_time() {
857 assert_eq!(
858 FileTime::from_unix_time(1_833_029_933_770, 955_161_600).unwrap_err(),
859 FileTimeRangeErrorKind::Overflow.into()
860 );
861 assert_eq!(
862 FileTime::from_unix_time(1_833_029_933_770, NANOS_PER_SEC - 1).unwrap_err(),
863 FileTimeRangeErrorKind::Overflow.into()
864 );
865 assert_eq!(
866 FileTime::from_unix_time(1_833_029_933_770, NANOS_PER_SEC).unwrap_err(),
867 FileTimeRangeErrorKind::Overflow.into()
868 );
869 assert_eq!(
870 FileTime::from_unix_time(1_833_029_933_770, u32::MAX).unwrap_err(),
871 FileTimeRangeErrorKind::Overflow.into()
872 );
873 assert_eq!(
874 FileTime::from_unix_time(i64::MAX, u32::MIN).unwrap_err(),
875 FileTimeRangeErrorKind::Overflow.into()
876 );
877 assert_eq!(
878 FileTime::from_unix_time(i64::MAX, NANOS_PER_SEC - 1).unwrap_err(),
879 FileTimeRangeErrorKind::Overflow.into()
880 );
881 assert_eq!(
882 FileTime::from_unix_time(i64::MAX, NANOS_PER_SEC).unwrap_err(),
883 FileTimeRangeErrorKind::Overflow.into()
884 );
885 assert_eq!(
886 FileTime::from_unix_time(i64::MAX, u32::MAX).unwrap_err(),
887 FileTimeRangeErrorKind::Overflow.into()
888 );
889 }
890
891 #[cfg(feature = "std")]
892 #[proptest]
893 fn from_unix_time_with_too_big_date_time_roundtrip(
894 #[strategy(1_833_029_933_770_i64..)] secs: i64,
895 #[strategy(..NANOS_PER_SEC)] nanos: u32,
896 ) {
897 if secs == 1_833_029_933_770 {
898 prop_assume!(nanos >= 955_161_600);
899 }
900
901 prop_assert_eq!(
902 FileTime::from_unix_time(secs, nanos).unwrap_err(),
903 FileTimeRangeErrorKind::Overflow.into()
904 );
905 }
906
907 #[test]
908 fn from_unix_time_secs_before_nt_time_epoch() {
909 assert_eq!(
910 FileTime::from_unix_time_secs(-11_644_473_601).unwrap_err(),
911 FileTimeRangeErrorKind::Negative.into()
912 );
913 assert_eq!(
914 FileTime::from_unix_time_secs(i64::MIN).unwrap_err(),
915 FileTimeRangeErrorKind::Negative.into()
916 );
917 }
918
919 #[cfg(feature = "std")]
920 #[proptest]
921 fn from_unix_time_secs_before_nt_time_epoch_roundtrip(
922 #[strategy(..=-11_644_473_601_i64)] ts: i64,
923 ) {
924 prop_assert_eq!(
925 FileTime::from_unix_time_secs(ts).unwrap_err(),
926 FileTimeRangeErrorKind::Negative.into()
927 );
928 }
929
930 #[test]
931 fn from_unix_time_secs() {
932 assert_eq!(
933 FileTime::from_unix_time_secs(-11_644_473_600).unwrap(),
934 FileTime::NT_TIME_EPOCH
935 );
936 assert_eq!(
937 FileTime::from_unix_time_secs(-11_644_473_599).unwrap(),
938 FileTime::new(FILE_TIMES_PER_SEC)
939 );
940 assert_eq!(
941 FileTime::from_unix_time_secs(i64::default() - 1).unwrap(),
942 FileTime::UNIX_EPOCH - Duration::from_secs(1)
943 );
944 assert_eq!(
945 FileTime::from_unix_time_secs(i64::default()).unwrap(),
946 FileTime::UNIX_EPOCH
947 );
948 assert_eq!(
949 FileTime::from_unix_time_secs(i64::default() + 1).unwrap(),
950 FileTime::UNIX_EPOCH + Duration::from_secs(1)
951 );
952 assert_eq!(
953 FileTime::from_unix_time_secs(910_692_730_085).unwrap(),
954 FileTime::SIGNED_MAX - Duration::from_nanos(477_580_700)
955 );
956 assert_eq!(
957 FileTime::from_unix_time_secs(1_833_029_933_770).unwrap(),
958 FileTime::MAX - Duration::from_nanos(955_161_500)
959 );
960 }
961
962 #[cfg(feature = "std")]
963 #[proptest]
964 fn from_unix_time_secs_roundtrip(#[strategy(-11_644_473_600..=1_833_029_933_770_i64)] ts: i64) {
965 prop_assert!(FileTime::from_unix_time_secs(ts).is_ok());
966 }
967
968 #[test]
969 fn from_unix_time_secs_with_too_big_date_time() {
970 assert_eq!(
971 FileTime::from_unix_time_secs(1_833_029_933_771).unwrap_err(),
972 FileTimeRangeErrorKind::Overflow.into()
973 );
974 assert_eq!(
975 FileTime::from_unix_time_secs(i64::MAX).unwrap_err(),
976 FileTimeRangeErrorKind::Overflow.into()
977 );
978 }
979
980 #[cfg(feature = "std")]
981 #[proptest]
982 fn from_unix_time_secs_with_too_big_date_time_roundtrip(
983 #[strategy(1_833_029_933_771_i64..)] ts: i64,
984 ) {
985 prop_assert_eq!(
986 FileTime::from_unix_time_secs(ts).unwrap_err(),
987 FileTimeRangeErrorKind::Overflow.into()
988 );
989 }
990
991 #[test]
992 fn from_unix_time_millis_before_nt_time_epoch() {
993 assert_eq!(
994 FileTime::from_unix_time_millis(-11_644_473_600_001).unwrap_err(),
995 FileTimeRangeErrorKind::Negative.into()
996 );
997 assert_eq!(
998 FileTime::from_unix_time_millis(i64::MIN).unwrap_err(),
999 FileTimeRangeErrorKind::Negative.into()
1000 );
1001 }
1002
1003 #[cfg(feature = "std")]
1004 #[proptest]
1005 fn from_unix_time_millis_before_nt_time_epoch_roundtrip(
1006 #[strategy(..=-11_644_473_600_001_i64)] ts: i64,
1007 ) {
1008 prop_assert_eq!(
1009 FileTime::from_unix_time_millis(ts).unwrap_err(),
1010 FileTimeRangeErrorKind::Negative.into()
1011 );
1012 }
1013
1014 #[test]
1015 fn from_unix_time_millis() {
1016 assert_eq!(
1017 FileTime::from_unix_time_millis(-11_644_473_600_000).unwrap(),
1018 FileTime::NT_TIME_EPOCH
1019 );
1020 assert_eq!(
1021 FileTime::from_unix_time_millis(-11_644_473_599_999).unwrap(),
1022 FileTime::new(10000)
1023 );
1024 assert_eq!(
1025 FileTime::from_unix_time_millis(i64::default() - 1).unwrap(),
1026 FileTime::UNIX_EPOCH - Duration::from_millis(1)
1027 );
1028 assert_eq!(
1029 FileTime::from_unix_time_millis(i64::default()).unwrap(),
1030 FileTime::UNIX_EPOCH
1031 );
1032 assert_eq!(
1033 FileTime::from_unix_time_millis(i64::default() + 1).unwrap(),
1034 FileTime::UNIX_EPOCH + Duration::from_millis(1)
1035 );
1036 assert_eq!(
1037 FileTime::from_unix_time_millis(910_692_730_085_477).unwrap(),
1038 FileTime::SIGNED_MAX - Duration::from_nanos(580_700)
1039 );
1040 assert_eq!(
1041 FileTime::from_unix_time_millis(1_833_029_933_770_955).unwrap(),
1042 FileTime::MAX - Duration::from_nanos(161_500)
1043 );
1044 }
1045
1046 #[cfg(feature = "std")]
1047 #[proptest]
1048 fn from_unix_time_millis_roundtrip(
1049 #[strategy(-11_644_473_600_000..=1_833_029_933_770_955_i64)] ts: i64,
1050 ) {
1051 prop_assert!(FileTime::from_unix_time_millis(ts).is_ok());
1052 }
1053
1054 #[test]
1055 fn from_unix_time_millis_with_too_big_date_time() {
1056 assert_eq!(
1057 FileTime::from_unix_time_millis(1_833_029_933_770_956).unwrap_err(),
1058 FileTimeRangeErrorKind::Overflow.into()
1059 );
1060 assert_eq!(
1061 FileTime::from_unix_time_millis(i64::MAX).unwrap_err(),
1062 FileTimeRangeErrorKind::Overflow.into()
1063 );
1064 }
1065
1066 #[cfg(feature = "std")]
1067 #[proptest]
1068 fn from_unix_time_millis_with_too_big_date_time_roundtrip(
1069 #[strategy(1_833_029_933_770_956_i64..)] ts: i64,
1070 ) {
1071 prop_assert_eq!(
1072 FileTime::from_unix_time_millis(ts).unwrap_err(),
1073 FileTimeRangeErrorKind::Overflow.into()
1074 );
1075 }
1076
1077 #[test]
1078 fn from_unix_time_micros_before_nt_time_epoch() {
1079 assert_eq!(
1080 FileTime::from_unix_time_micros(-11_644_473_600_000_001).unwrap_err(),
1081 FileTimeRangeErrorKind::Negative.into()
1082 );
1083 assert_eq!(
1084 FileTime::from_unix_time_micros(i64::MIN).unwrap_err(),
1085 FileTimeRangeErrorKind::Negative.into()
1086 );
1087 }
1088
1089 #[cfg(feature = "std")]
1090 #[proptest]
1091 fn from_unix_time_micros_before_nt_time_epoch_roundtrip(
1092 #[strategy(..=-11_644_473_600_000_001_i64)] ts: i64,
1093 ) {
1094 prop_assert_eq!(
1095 FileTime::from_unix_time_micros(ts).unwrap_err(),
1096 FileTimeRangeErrorKind::Negative.into()
1097 );
1098 }
1099
1100 #[test]
1101 fn from_unix_time_micros() {
1102 assert_eq!(
1103 FileTime::from_unix_time_micros(-11_644_473_600_000_000).unwrap(),
1104 FileTime::NT_TIME_EPOCH
1105 );
1106 assert_eq!(
1107 FileTime::from_unix_time_micros(-11_644_473_599_999_999).unwrap(),
1108 FileTime::new(10)
1109 );
1110 assert_eq!(
1111 FileTime::from_unix_time_micros(i64::default() - 1).unwrap(),
1112 FileTime::UNIX_EPOCH - Duration::from_micros(1)
1113 );
1114 assert_eq!(
1115 FileTime::from_unix_time_micros(i64::default()).unwrap(),
1116 FileTime::UNIX_EPOCH
1117 );
1118 assert_eq!(
1119 FileTime::from_unix_time_micros(i64::default() + 1).unwrap(),
1120 FileTime::UNIX_EPOCH + Duration::from_micros(1)
1121 );
1122 assert_eq!(
1123 FileTime::from_unix_time_micros(910_692_730_085_477_580).unwrap(),
1124 FileTime::SIGNED_MAX - Duration::from_nanos(700)
1125 );
1126 assert_eq!(
1127 FileTime::from_unix_time_micros(1_833_029_933_770_955_161).unwrap(),
1128 FileTime::MAX - Duration::from_nanos(500)
1129 );
1130 }
1131
1132 #[cfg(feature = "std")]
1133 #[proptest]
1134 fn from_unix_time_micros_roundtrip(
1135 #[strategy(-11_644_473_600_000_000..=1_833_029_933_770_955_161_i64)] ts: i64,
1136 ) {
1137 prop_assert!(FileTime::from_unix_time_micros(ts).is_ok());
1138 }
1139
1140 #[test]
1141 fn from_unix_time_micros_with_too_big_date_time() {
1142 assert_eq!(
1143 FileTime::from_unix_time_micros(1_833_029_933_770_955_162).unwrap_err(),
1144 FileTimeRangeErrorKind::Overflow.into()
1145 );
1146 assert_eq!(
1147 FileTime::from_unix_time_micros(i64::MAX).unwrap_err(),
1148 FileTimeRangeErrorKind::Overflow.into()
1149 );
1150 }
1151
1152 #[cfg(feature = "std")]
1153 #[proptest]
1154 fn from_unix_time_micros_with_too_big_date_time_roundtrip(
1155 #[strategy(1_833_029_933_770_955_162_i64..)] ts: i64,
1156 ) {
1157 prop_assert_eq!(
1158 FileTime::from_unix_time_micros(ts).unwrap_err(),
1159 FileTimeRangeErrorKind::Overflow.into()
1160 );
1161 }
1162
1163 #[test]
1164 fn from_unix_time_nanos_before_nt_time_epoch() {
1165 assert_eq!(
1166 FileTime::from_unix_time_nanos(-11_644_473_600_000_000_100).unwrap_err(),
1167 FileTimeRangeErrorKind::Negative.into()
1168 );
1169 assert_eq!(
1170 FileTime::from_unix_time_nanos(-11_644_473_600_000_000_099).unwrap_err(),
1171 FileTimeRangeErrorKind::Negative.into()
1172 );
1173 assert_eq!(
1174 FileTime::from_unix_time_nanos(-11_644_473_600_000_000_001).unwrap_err(),
1175 FileTimeRangeErrorKind::Negative.into()
1176 );
1177 assert_eq!(
1178 FileTime::from_unix_time_nanos(i128::MIN).unwrap_err(),
1179 FileTimeRangeErrorKind::Negative.into()
1180 );
1181 }
1182
1183 #[cfg(feature = "std")]
1184 #[proptest]
1185 fn from_unix_time_nanos_before_nt_time_epoch_roundtrip(
1186 #[strategy(..=-11_644_473_600_000_000_001_i128)] ts: i128,
1187 ) {
1188 prop_assert_eq!(
1189 FileTime::from_unix_time_nanos(ts).unwrap_err(),
1190 FileTimeRangeErrorKind::Negative.into()
1191 );
1192 }
1193
1194 #[test]
1195 fn from_unix_time_nanos() {
1196 assert_eq!(
1197 FileTime::from_unix_time_nanos(-11_644_473_600_000_000_000).unwrap(),
1198 FileTime::NT_TIME_EPOCH
1199 );
1200 assert_eq!(
1201 FileTime::from_unix_time_nanos(-11_644_473_599_999_999_999).unwrap(),
1202 FileTime::NT_TIME_EPOCH
1203 );
1204 assert_eq!(
1205 FileTime::from_unix_time_nanos(-11_644_473_599_999_999_901).unwrap(),
1206 FileTime::NT_TIME_EPOCH
1207 );
1208 assert_eq!(
1209 FileTime::from_unix_time_nanos(-11_644_473_599_999_999_900).unwrap(),
1210 FileTime::new(1)
1211 );
1212 assert_eq!(
1213 FileTime::from_unix_time_nanos(-11_644_473_599_000_000_100).unwrap(),
1214 FileTime::new(FILE_TIMES_PER_SEC - 1)
1215 );
1216 assert_eq!(
1217 FileTime::from_unix_time_nanos(-11_644_473_599_000_000_099).unwrap(),
1218 FileTime::new(FILE_TIMES_PER_SEC - 1)
1219 );
1220 assert_eq!(
1221 FileTime::from_unix_time_nanos(-11_644_473_599_000_000_001).unwrap(),
1222 FileTime::new(FILE_TIMES_PER_SEC - 1)
1223 );
1224 assert_eq!(
1225 FileTime::from_unix_time_nanos(-11_644_473_599_000_000_000).unwrap(),
1226 FileTime::new(FILE_TIMES_PER_SEC)
1227 );
1228 assert_eq!(
1229 FileTime::from_unix_time_nanos(i128::default() - 100).unwrap(),
1230 FileTime::UNIX_EPOCH - Duration::from_nanos(100)
1231 );
1232 assert_eq!(
1233 FileTime::from_unix_time_nanos(i128::default() - 99).unwrap(),
1234 FileTime::UNIX_EPOCH - Duration::from_nanos(100)
1235 );
1236 assert_eq!(
1237 FileTime::from_unix_time_nanos(i128::default() - 1).unwrap(),
1238 FileTime::UNIX_EPOCH - Duration::from_nanos(100)
1239 );
1240 assert_eq!(
1241 FileTime::from_unix_time_nanos(i128::default()).unwrap(),
1242 FileTime::UNIX_EPOCH
1243 );
1244 assert_eq!(
1245 FileTime::from_unix_time_nanos(i128::default() + 1).unwrap(),
1246 FileTime::UNIX_EPOCH
1247 );
1248 assert_eq!(
1249 FileTime::from_unix_time_nanos(i128::default() + 99).unwrap(),
1250 FileTime::UNIX_EPOCH
1251 );
1252 assert_eq!(
1253 FileTime::from_unix_time_nanos(i128::default() + 100).unwrap(),
1254 FileTime::UNIX_EPOCH + Duration::from_nanos(100)
1255 );
1256 assert_eq!(
1257 FileTime::from_unix_time_nanos(910_692_730_085_477_580_700).unwrap(),
1258 FileTime::SIGNED_MAX
1259 );
1260 assert_eq!(
1261 FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_500).unwrap(),
1262 FileTime::MAX
1263 );
1264 }
1265
1266 #[cfg(feature = "std")]
1267 #[proptest]
1268 fn from_unix_time_nanos_roundtrip(
1269 #[strategy(-11_644_473_600_000_000_000..=1_833_029_933_770_955_161_500_i128)] ts: i128,
1270 ) {
1271 prop_assert!(FileTime::from_unix_time_nanos(ts).is_ok());
1272 }
1273
1274 #[test]
1275 fn from_unix_time_nanos_with_too_big_date_time() {
1276 assert_eq!(
1277 FileTime::from_unix_time_nanos(1_833_029_933_770_955_161_501).unwrap_err(),
1278 FileTimeRangeErrorKind::Overflow.into()
1279 );
1280 assert_eq!(
1281 FileTime::from_unix_time_nanos(i128::MAX).unwrap_err(),
1282 FileTimeRangeErrorKind::Overflow.into()
1283 );
1284 }
1285
1286 #[cfg(feature = "std")]
1287 #[proptest]
1288 fn from_unix_time_nanos_with_too_big_date_time_roundtrip(
1289 #[strategy(1_833_029_933_770_955_161_501_i128..)] ts: i128,
1290 ) {
1291 prop_assert_eq!(
1292 FileTime::from_unix_time_nanos(ts).unwrap_err(),
1293 FileTimeRangeErrorKind::Overflow.into()
1294 );
1295 }
1296}