Skip to main content

max / makenotwork

1.6 KB · 56 lines History Blame Raw
1 //! Date/time parsing helpers for user-supplied schedule inputs.
2
3 /// Parse an optional datetime string for scheduled publishing.
4 ///
5 /// Accepts ISO 8601 (RFC 3339) or HTML `datetime-local` format (`%Y-%m-%dT%H:%M`).
6 /// Returns `Some(Some(dt))` for a valid datetime, `Some(None)` for empty string
7 /// (clear schedule), or `None` for absent input (no change).
8 pub fn parse_schedule_datetime(s: Option<&str>) -> Option<Option<chrono::DateTime<chrono::Utc>>> {
9 s.map(|s| {
10 if s.is_empty() {
11 None
12 } else {
13 chrono::DateTime::parse_from_rfc3339(s)
14 .map(|dt| dt.with_timezone(&chrono::Utc))
15 .or_else(|_| {
16 chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M")
17 .map(|naive| naive.and_utc())
18 })
19 .ok()
20 }
21 })
22 }
23
24 #[cfg(test)]
25 mod tests {
26 use super::*;
27
28 #[test]
29 fn parse_schedule_datetime_none_input() {
30 assert!(parse_schedule_datetime(None).is_none());
31 }
32
33 #[test]
34 fn parse_schedule_datetime_empty_clears() {
35 assert_eq!(parse_schedule_datetime(Some("")), Some(None));
36 }
37
38 #[test]
39 fn parse_schedule_datetime_rfc3339() {
40 assert!(
41 parse_schedule_datetime(Some("2026-04-29T12:00:00Z"))
42 .unwrap()
43 .is_some()
44 );
45 }
46
47 #[test]
48 fn parse_schedule_datetime_html_local() {
49 assert!(
50 parse_schedule_datetime(Some("2026-04-29T12:00"))
51 .unwrap()
52 .is_some()
53 );
54 }
55 }
56