1pub const APPLE_EPOCH_MS: i64 = 978_307_200_000;
18
19pub const MULTIPLIER: i64 = 1_000_000;
22
23pub fn apple_to_unix_ms(raw: i64) -> Option<i64> {
27 if raw <= 0 {
28 return None;
29 }
30 Some(APPLE_EPOCH_MS + (raw / MULTIPLIER))
31}
32
33pub fn unix_ms_to_apple(ms: i64) -> i64 {
35 (ms - APPLE_EPOCH_MS) * MULTIPLIER
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn apple_epoch_is_correct() {
44 assert_eq!(APPLE_EPOCH_MS, 978_307_200_000);
46 }
47
48 #[test]
49 fn zero_returns_none() {
50 assert_eq!(apple_to_unix_ms(0), None);
51 }
52
53 #[test]
54 fn negative_returns_none() {
55 assert_eq!(apple_to_unix_ms(-1), None);
56 }
57
58 #[test]
59 fn one_second_after_apple_epoch() {
60 let raw = 1000 * MULTIPLIER;
62 let result = apple_to_unix_ms(raw).unwrap();
63 assert_eq!(result, APPLE_EPOCH_MS + 1000);
64 }
65
66 #[test]
67 fn ten_seconds_after_apple_epoch() {
68 let raw = 10_000 * MULTIPLIER;
69 let result = apple_to_unix_ms(raw).unwrap();
70 assert_eq!(result, APPLE_EPOCH_MS + 10_000);
71 }
72
73 #[test]
74 fn roundtrip() {
75 let now_ms: i64 = 1_700_000_000_000; let apple = unix_ms_to_apple(now_ms);
77 let back = apple_to_unix_ms(apple).unwrap();
78 assert_eq!(back, now_ms);
79 }
80
81 #[test]
82 fn real_message_date() {
83 let unix_ms: i64 = 1_771_445_533_049;
87 let raw = unix_ms_to_apple(unix_ms);
88 assert!(raw > 0);
89 let back = apple_to_unix_ms(raw).unwrap();
90 assert_eq!(back, unix_ms);
91 }
92
93 #[test]
94 fn multiplier_value() {
95 assert_eq!(MULTIPLIER, 1_000_000);
96 }
97
98 #[test]
99 fn sub_millisecond_truncates() {
100 let raw: i64 = 793_138_336_556_999_936;
104 let result = apple_to_unix_ms(raw).unwrap();
105 assert_eq!(result, APPLE_EPOCH_MS + 793_138_336_556);
107 }
108
109 #[test]
110 fn real_db_values_match_node() {
111 let cases: Vec<(i64, i64)> = vec![
113 (793_138_336_352_743_000, 1_771_445_536_352),
114 (793_138_336_557_000_000, 1_771_445_536_557),
115 (793_138_338_791_721_000, 1_771_445_538_791),
116 (793_138_267_580_708_000, 1_771_445_467_580),
117 (793_138_269_954_512_000, 1_771_445_469_954),
118 ];
119 for (raw, expected) in cases {
120 let result = apple_to_unix_ms(raw).unwrap();
121 assert_eq!(result, expected, "raw={raw}");
122 }
123 }
124}