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