objc2_core_foundation/
date.rs1use core::{cmp::Ordering, ptr};
2
3use crate::CFDate;
4
5impl CFDate {
6 #[cfg(feature = "std")]
12 pub fn from_system_time(time: &std::time::SystemTime) -> crate::CFRetained<Self> {
13 let since_1970 = match time.duration_since(std::time::UNIX_EPOCH) {
14 Ok(duration) => duration.as_secs_f64(),
15 Err(err) => -err.duration().as_secs_f64(),
16 } as core::ffi::c_double;
17
18 let since_2001 = since_1970 - unsafe { crate::kCFAbsoluteTimeIntervalSince1970 };
19 Self::new(None, since_2001).expect("failed creating CFDate")
20 }
21
22 #[cfg(feature = "std")]
31 #[allow(clippy::unnecessary_cast)]
32 pub fn to_system_time(&self) -> Option<std::time::SystemTime> {
33 let since_2001 = self.absolute_time();
34 let since_1970 = (since_2001 + unsafe { crate::kCFAbsoluteTimeIntervalSince1970 }) as f64;
35
36 std::time::UNIX_EPOCH.checked_add(std::time::Duration::try_from_secs_f64(since_1970).ok()?)
37 }
38}
39
40impl PartialOrd for CFDate {
41 #[inline]
42 #[doc(alias = "CFDateCompare")]
43 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
44 Some(self.cmp(other))
45 }
46}
47
48impl Ord for CFDate {
49 #[inline]
50 #[doc(alias = "CFDateCompare")]
51 fn cmp(&self, other: &Self) -> Ordering {
52 let context = ptr::null_mut();
54 unsafe { self.compare(Some(other), context) }.into()
55 }
56}
57
58#[cfg(test)]
59mod test {
60 use core::ffi::c_double;
61 use std::time::{Duration, SystemTime};
62
63 use crate::CFAbsoluteTimeGetCurrent;
64
65 use super::*;
66
67 #[test]
68 fn cmp() {
69 let now = CFDate::new(None, CFAbsoluteTimeGetCurrent()).unwrap();
70 let past = CFDate::new(None, now.absolute_time() - 1.0).unwrap();
71 assert_eq!(now.cmp(&past), Ordering::Greater);
72 assert_eq!(now.cmp(&now), Ordering::Equal);
73 assert_eq!(past.cmp(&now), Ordering::Less);
74
75 assert_eq!(now, now);
76 assert_ne!(now, past);
77 }
78
79 #[test]
80 fn system_time_roundtrip() {
81 let date1 = CFDate::new(None, CFAbsoluteTimeGetCurrent()).unwrap();
82 let date2 = CFDate::from_system_time(&date1.to_system_time().unwrap());
83 let diff = date1.absolute_time() - date2.absolute_time();
84 assert!(diff <= 1.0); }
86
87 #[test]
88 fn system_time_cmp() {
89 let std_now_first = SystemTime::now();
90 let cf_now_first = CFDate::new(None, CFAbsoluteTimeGetCurrent() + 1.0).unwrap();
91 let std_now_second = std_now_first.checked_add(Duration::from_secs(2)).unwrap();
92 let cf_now_second = CFDate::new(None, CFAbsoluteTimeGetCurrent() + 3.0).unwrap();
93
94 assert!(std_now_first <= std_now_second);
95 assert!(cf_now_first <= cf_now_second);
96
97 assert!(std_now_first <= cf_now_first.to_system_time().unwrap());
98 assert!(cf_now_first.to_system_time().unwrap() <= std_now_second);
99
100 assert!(cf_now_first <= CFDate::from_system_time(&std_now_second));
101 assert!(CFDate::from_system_time(&std_now_second) <= cf_now_second);
102 }
103
104 #[test]
105 fn system_time_from_odd() {
106 let time = SystemTime::UNIX_EPOCH
107 .checked_sub(Duration::from_secs(10))
108 .unwrap();
109 let _ = CFDate::from_system_time(&time);
110 }
111
112 #[test]
113 fn system_time_unrepresentable() {
114 let date = CFDate::new(None, c_double::MIN).unwrap();
115 assert_eq!(date.to_system_time(), None);
116
117 let date = CFDate::new(None, c_double::MAX).unwrap();
118 assert_eq!(date.to_system_time(), None);
119 }
120}