From ed9bd87ab505139f6f9921b8440230df57d04a00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20V=C3=B6gele?= Date: Tue, 22 Nov 2022 14:55:50 +0100 Subject: [PATCH] Add support for comma separated EXDATEs --- src/appointment.rs | 62 ++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/src/appointment.rs b/src/appointment.rs index 1abafc4..02084a9 100644 --- a/src/appointment.rs +++ b/src/appointment.rs @@ -141,12 +141,17 @@ impl Event { match property.name.as_str() { "UID" => uid = uid.or(Some(value)), "RRULE" => rrule = rrule.or(Some(value)), - "DTSTART" => start = start.or(parse_date(property.params, &value)), - "DTEND" => end = end.or(parse_date(property.params, &value)), - "RECURRENCE-ID" => { - recurrence_id = recurrence_id.or(parse_date(property.params, &value)) + "DTSTART" => { + start = start.or(parse_dates(property.params, &value).into_iter().next()) } - "EXDATE" => parse_date(property.params, &value) + "DTEND" => { + end = end.or(parse_dates(property.params, &value).into_iter().next()) + } + "RECURRENCE-ID" => { + recurrence_id = recurrence_id + .or(parse_dates(property.params, &value).into_iter().next()) + } + "EXDATE" => parse_dates(property.params, &value) .into_iter() .for_each(|date| exdates.push(date)), _ => {} @@ -167,9 +172,13 @@ impl Event { } } -fn parse_date(params: Option)>>, value: &str) -> Option> { - let params = params?; - let datetime = NaiveDateTime::parse_from_str(value, "%Y%m%dT%H%M%S").ok()?; +// TODO This should return a result instead +fn parse_dates(params: Option)>>, value: &str) -> Vec> { + let params = if let Some(params) = params { + params + } else { + return vec![]; + }; // Find TZID parameter and extract its singular value let tz = params .into_iter() @@ -181,18 +190,27 @@ fn parse_date(params: Option)>>, value: &str) -> Option .into_iter() .next() .unwrap(); - let tz: chrono_tz::Tz = tz.parse().ok()?; - let datetime = match tz.from_local_datetime(&datetime) { - LocalResult::Single(datetime) => Some(datetime), - LocalResult::None => None, - LocalResult::Ambiguous(_, _) => { - warn!( - "Ignoring ambiguous datetime '{}' from timezone '{}'", - datetime, - tz.name() - ); - None - } - }?; - Some(datetime.with_timezone(&datetime.timezone().into())) + let tz: chrono_tz::Tz = if let Ok(tz) = tz.parse() { + tz + } else { + return vec![]; + }; + + value + .split(',') + .filter_map(|time_str| NaiveDateTime::parse_from_str(time_str, "%Y%m%dT%H%M%S").ok()) + .filter_map(|datetime| match tz.from_local_datetime(&datetime) { + LocalResult::Single(datetime) => Some(datetime), + LocalResult::None => None, + LocalResult::Ambiguous(_, _) => { + warn!( + "Ignoring ambiguous datetime '{}' from timezone '{}'", + datetime, + tz.name() + ); + None + } + }) + .map(|datetime| datetime.with_timezone(&datetime.timezone().into())) + .collect::>() }