From 05e9450ea926833d2bf466dea720192886e97ff5 Mon Sep 17 00:00:00 2001 From: Fredrik Meringdal Date: Fri, 13 Nov 2020 19:53:44 +0100 Subject: Bug fix: unable to parse dtstart when it is date instead of datetime --- Cargo.toml | 2 +- src/options.rs | 14 ++++++++++++++ src/rrulestr.rs | 46 ++++++++++++++++++++++++++++++---------------- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 17654ee..3767b93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "rrule" description = "A pure Rust implementation of recurrence rules as defined in the iCalendar RFC." license = "MIT" -version = "0.3.3" +version = "0.3.4" documentation = "https://docs.rs/rrule" repository = "https://github.com/fmeringdal/rust_rrule" authors = ["Fredrik Meringdal"] diff --git a/src/options.rs b/src/options.rs index dc2d186..4e6f1cd 100644 --- a/src/options.rs +++ b/src/options.rs @@ -248,3 +248,17 @@ impl Display for RRuleParseError { } impl Error for RRuleParseError {} + + +pub fn weekday_from_str(val: &str) -> Result { + match val { + "MO" => Ok(Weekday::Mon), + "TU" => Ok(Weekday::Tue), + "WE" => Ok(Weekday::Wed), + "TH" => Ok(Weekday::Thu), + "FR" => Ok(Weekday::Fri), + "SA" => Ok(Weekday::Sat), + "SU" => Ok(Weekday::Sun), + _ => Err(format!("Invalid weekday: {}", val)), + } +} \ No newline at end of file diff --git a/src/rrulestr.rs b/src/rrulestr.rs index eb5a5be..1d263ed 100644 --- a/src/rrulestr.rs +++ b/src/rrulestr.rs @@ -3,6 +3,7 @@ use crate::options::*; use crate::parse_options::parse_options; use crate::rrule::RRule; use crate::rruleset::RRuleSet; +use crate::datetime::get_weekday_val; use chrono::prelude::*; use chrono_tz::{Tz, UTC}; use regex::Regex; @@ -37,12 +38,13 @@ fn parse_datestring_bit( } fn datestring_to_date(dt: &str, tz: &Tz) -> Result { + let bits = DATESTR_RE.captures(dt); if bits.is_none() { return Err(RRuleParseError(format!("Invalid datetime: {}", dt))); } let bits = bits.unwrap(); - if bits.len() < 7 { + if bits.len() < 3 { return Err(RRuleParseError(format!("Invalid datetime: {}", dt))); } @@ -53,9 +55,9 @@ fn datestring_to_date(dt: &str, tz: &Tz) -> Result { parse_datestring_bit(&bits, 3, dt)?, ) .and_hms( - parse_datestring_bit(&bits, 5, dt)?, - parse_datestring_bit(&bits, 6, dt)?, - parse_datestring_bit(&bits, 7, dt)?, + parse_datestring_bit(&bits, 5, dt).unwrap_or(0), + parse_datestring_bit(&bits, 6, dt).unwrap_or(0), + parse_datestring_bit(&bits, 7, dt).unwrap_or(0), )); } @@ -69,7 +71,7 @@ fn parse_dtstart(s: &str) -> Result { } else { UTC }; - + let dtstart_str = match caps.get(2) { Some(dt) => dt.as_str(), None => return Err(RRuleParseError(format!("Invalid datetime: {}", s))), @@ -153,14 +155,14 @@ fn parse_rrule(line: &str) -> Result { None => return Err(RRuleParseError(format!("Invalid frequenzy: {}", value))), }, "WKST" => { - let wkst = stringval_to_int(value, format!("Invalid weekstart value"))?; - if wkst > 6 { - return Err(RRuleParseError(format!( - "Invalid wkst value: {}. It must be between 0 and 6", - wkst - ))); - }; - options.wkst = Some(wkst); + match weekday_from_str(value) { + Ok(weekday) => { + options.wkst = Some(get_weekday_val(&weekday)); + } + Err(e) => { + return Err(RRuleParseError(e)); + } + } } "COUNT" => { let count = stringval_to_int(value, format!("Invalid count"))?; @@ -501,7 +503,12 @@ fn parse_rdate( Ok(rdatevals) } +fn preprocess_rrule_string(s: &str) -> String { + s.replace("DTSTART;VALUE=DATETIME", "DTSTART").replace("DTSTART;VALUE=DATE", "DTSTART") +} + pub fn build_rruleset(s: &str) -> Result { + let s = preprocess_rrule_string(s); let ParsedInput { mut rrule_vals, rdate_vals, @@ -510,7 +517,7 @@ pub fn build_rruleset(s: &str) -> Result { dtstart, tzid, .. - } = parse_input(s)?; + } = parse_input(&s)?; let mut rset = RRuleSet::new(); rset.dtstart = dtstart; @@ -544,12 +551,14 @@ pub fn build_rruleset(s: &str) -> Result { } pub fn build_rrule(s: &str) -> Result { + let s = preprocess_rrule_string(s); + let ParsedInput { mut rrule_vals, tzid, dtstart, .. - } = parse_input(s)?; + } = parse_input(&s)?; rrule_vals[0].tzid = tzid; rrule_vals[0].dtstart = dtstart; @@ -585,7 +594,6 @@ mod test { #[test] fn it_works_4() { let res = build_rruleset("DTSTART:20120201T120000Z\nRRULE:FREQ=DAILY;COUNT=5\nEXDATE;TZID=Europe/Berlin:20120202T130000Z,20120203T130000Z"); - println!("{:?}", res); assert!(res.is_ok()); } @@ -662,6 +670,12 @@ mod test { assert_eq!(res.err().unwrap().0, "Invalid byminute value"); } + #[test] + fn parses_dtstart_when_just_date() { + let res = build_rruleset("DTSTART;VALUE=DATE:20200812\nRRULE:FREQ=WEEKLY;UNTIL=20210511T220000Z;INTERVAL=1;BYDAY=WE;WKST=MO"); + assert!(res.is_ok()); + } + #[test] #[ignore = "Only for benching"] fn bench() { -- cgit v1.2.3