1use chrono::{DateTime, SecondsFormat, Utc};
5
6pub fn now_rfc3339_utc_nanos() -> String {
12 Utc::now().to_rfc3339_opts(SecondsFormat::Nanos, true)
13}
14
15pub fn parse_iso_timestamp(ts: &str) -> i64 {
36 if ts.is_empty() {
37 return 0;
38 }
39
40 if let Ok(dt) = DateTime::parse_from_rfc3339(ts) {
42 return dt.timestamp_millis();
43 }
44
45 let formats = [
47 "%Y-%m-%dT%H:%M:%S%.3fZ",
48 "%Y-%m-%dT%H:%M:%S%.fZ",
49 "%Y-%m-%dT%H:%M:%SZ",
50 ];
51
52 for format in &formats {
53 if let Ok(dt) = DateTime::parse_from_str(ts, format) {
54 return dt.timestamp_millis();
55 }
56 }
57
58 0
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn test_parse_iso_timestamp_rfc3339() {
67 let ts = "2024-01-15T10:30:45.123Z";
69 let result = parse_iso_timestamp(ts);
70 assert!(result > 0);
71
72 assert!(result > 1_700_000_000_000); assert!(result < 1_800_000_000_000); }
76
77 #[test]
78 fn test_parse_iso_timestamp_with_timezone() {
79 let ts = "2024-01-15T10:30:45.123+08:00";
81 let result = parse_iso_timestamp(ts);
82 assert!(result > 0);
83 }
84
85 #[test]
86 fn test_parse_iso_timestamp_no_millis() {
87 let ts = "2024-01-15T10:30:45Z";
89 let result = parse_iso_timestamp(ts);
90 assert!(result > 0);
91 }
92
93 #[test]
94 fn test_parse_iso_timestamp_fallback_formats() {
95 let ts1 = "2024-01-15T10:30:45.123Z";
97 let result1 = parse_iso_timestamp(ts1);
98 assert!(result1 > 0);
99
100 let ts2 = "2024-01-15T10:30:45.123456Z";
102 let result2 = parse_iso_timestamp(ts2);
103 assert!(result2 > 0);
104
105 let ts3 = "2024-01-15T10:30:45Z";
107 let result3 = parse_iso_timestamp(ts3);
108 assert!(result3 > 0);
109 }
110
111 #[test]
112 fn test_parse_iso_timestamp_empty() {
113 let result = parse_iso_timestamp("");
115 assert_eq!(result, 0);
116 }
117
118 #[test]
119 fn test_parse_iso_timestamp_invalid() {
120 let result = parse_iso_timestamp("not a timestamp");
122 assert_eq!(result, 0);
123
124 let result = parse_iso_timestamp("2024-13-45");
125 assert_eq!(result, 0);
126
127 let result = parse_iso_timestamp("invalid-date-time");
128 assert_eq!(result, 0);
129 }
130
131 #[test]
132 fn test_parse_iso_timestamp_different_years() {
133 let ts_2020 = "2020-06-15T12:00:00Z";
135 let ts_2024 = "2024-06-15T12:00:00Z";
136
137 let result_2020 = parse_iso_timestamp(ts_2020);
138 let result_2024 = parse_iso_timestamp(ts_2024);
139
140 assert!(result_2020 > 0);
141 assert!(result_2024 > 0);
142 assert!(result_2024 > result_2020);
143 }
144
145 #[test]
146 fn test_parse_iso_timestamp_milliseconds_precision() {
147 let ts1 = "2024-01-15T10:30:45.000Z";
149 let ts2 = "2024-01-15T10:30:45.999Z";
150
151 let result1 = parse_iso_timestamp(ts1);
152 let result2 = parse_iso_timestamp(ts2);
153
154 assert!(result1 > 0);
155 assert!(result2 > 0);
156 assert!(result2 > result1);
158 assert!(result2 - result1 < 1000);
159 }
160
161 #[test]
162 fn test_parse_iso_timestamp_same_time() {
163 let ts = "2024-01-15T10:30:45.123Z";
165 let result1 = parse_iso_timestamp(ts);
166 let result2 = parse_iso_timestamp(ts);
167
168 assert_eq!(result1, result2);
169 }
170
171 #[test]
172 fn test_parse_iso_timestamp_edge_cases() {
173 let ts1 = "2024-01-01T00:00:00Z";
177 let result1 = parse_iso_timestamp(ts1);
178 assert!(result1 > 0);
179
180 let ts2 = "2024-12-31T23:59:59Z";
182 let result2 = parse_iso_timestamp(ts2);
183 assert!(result2 > 0);
184 assert!(result2 > result1);
185
186 let ts3 = "2024-02-29T12:00:00Z";
188 let result3 = parse_iso_timestamp(ts3);
189 assert!(result3 > 0);
190 }
191
192 #[test]
193 fn test_parse_iso_timestamp_negative_timezone() {
194 let ts = "2024-01-15T10:30:45.123-05:00";
196 let result = parse_iso_timestamp(ts);
197 assert!(result > 0);
198 }
199
200 #[test]
201 fn test_parse_iso_timestamp_midnight() {
202 let ts = "2024-01-15T00:00:00.000Z";
204 let result = parse_iso_timestamp(ts);
205 assert!(result > 0);
206 }
207
208 #[test]
209 fn test_parse_iso_timestamp_noon() {
210 let ts = "2024-01-15T12:00:00.000Z";
212 let result = parse_iso_timestamp(ts);
213 assert!(result > 0);
214 }
215
216 #[test]
217 fn test_parse_iso_timestamp_whitespace() {
218 let result = parse_iso_timestamp(" 2024-01-15T10:30:45Z ");
220 assert_eq!(result, 0);
221 }
222
223 #[test]
224 fn test_parse_iso_timestamp_partial() {
225 let result = parse_iso_timestamp("2024-01-15");
227 assert_eq!(result, 0);
228
229 let result = parse_iso_timestamp("2024-01-15T10:30");
230 assert_eq!(result, 0);
231 }
232
233 #[test]
234 fn test_parse_iso_timestamp_ordering() {
235 let timestamps = [
237 "2024-01-15T10:00:00Z",
238 "2024-01-15T11:00:00Z",
239 "2024-01-15T12:00:00Z",
240 "2024-01-15T13:00:00Z",
241 ];
242
243 let results: Vec<i64> = timestamps
244 .iter()
245 .map(|ts| parse_iso_timestamp(ts))
246 .collect();
247
248 assert!(results.iter().all(|&r| r > 0));
250
251 for i in 1..results.len() {
253 assert!(results[i] > results[i - 1]);
254 }
255 }
256}