diff --git a/crates/store/src/calendar.rs b/crates/store/src/calendar.rs index 232b165..204ebad 100644 --- a/crates/store/src/calendar.rs +++ b/crates/store/src/calendar.rs @@ -1,5 +1,6 @@ use std::io::BufReader; +use crate::timestamps::{parse_datetime, parse_duration}; use anyhow::{anyhow, Result}; use async_trait::async_trait; use chrono::{Duration, NaiveDateTime, Timelike}; @@ -7,14 +8,9 @@ use ical::{ generator::{Emitter, IcalCalendar}, parser::Component, }; -use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -lazy_static! { - static ref RE_DURATION: regex::Regex = regex::Regex::new(r"^(?[+-])?P((?P\d+)W)?((?P\d+)D)?(T((?P\d+)H)?((?P\d+)M)?((?P\d+)S)?)?$").unwrap(); -} - #[derive(Debug, Clone)] pub struct Event { uid: String, @@ -136,67 +132,6 @@ impl Event { } } -pub fn parse_duration(string: &str) -> Result { - let captures = RE_DURATION - .captures(string) - .ok_or(anyhow!("invalid duration format"))?; - - let mut duration = Duration::zero(); - if let Some(weeks) = captures.name("W") { - duration = duration + Duration::weeks(weeks.as_str().parse()?); - } - if let Some(days) = captures.name("D") { - duration = duration + Duration::days(days.as_str().parse()?); - } - if let Some(hours) = captures.name("H") { - duration = duration + Duration::hours(hours.as_str().parse()?); - } - if let Some(minutes) = captures.name("M") { - duration = duration + Duration::minutes(minutes.as_str().parse()?); - } - if let Some(seconds) = captures.name("S") { - duration = duration + Duration::seconds(seconds.as_str().parse()?); - } - if let Some(sign) = captures.name("sign") { - if sign.as_str() == "-" { - duration = -duration; - } - } - - Ok(duration) -} - -#[test] -pub fn test_parse_duration() { - assert_eq!(parse_duration("P12W").unwrap(), Duration::weeks(12)); - assert_eq!(parse_duration("P12D").unwrap(), Duration::days(12)); - assert_eq!(parse_duration("PT12H").unwrap(), Duration::hours(12)); - assert_eq!(parse_duration("PT12M").unwrap(), Duration::minutes(12)); - assert_eq!(parse_duration("PT12S").unwrap(), Duration::seconds(12)); -} - -pub fn parse_datetime(string: &str) -> Result { - // TODO: respect timezones - // - // Format: ^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(?PZ)?$ - // if Z? - // UTC time - // else - // if TZID given? - // time in TZ - // else - // local time of attendee (can be different actual times for different attendees) - // BUT for this implementation will be UTC for now since this case is annoying - // (sabre-dav does same) - let (datetime, _tz_remainder) = NaiveDateTime::parse_and_remainder(string, "%Y%m%dT%H%M%S")?; - Ok(datetime) -} - -#[test] -fn test_parse_datetime() { - dbg!(parse_datetime("19960329T133000Z").unwrap()); -} - #[derive(Debug, Default, Clone, Deserialize, Serialize)] pub struct Calendar { pub id: String, diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs index 122bad4..ee58b8f 100644 --- a/crates/store/src/lib.rs +++ b/crates/store/src/lib.rs @@ -1,2 +1,3 @@ pub mod calendar; +pub mod timestamps; pub mod toml_store; diff --git a/crates/store/src/timestamps.rs b/crates/store/src/timestamps.rs new file mode 100644 index 0000000..75e5129 --- /dev/null +++ b/crates/store/src/timestamps.rs @@ -0,0 +1,67 @@ +use lazy_static::lazy_static; +lazy_static! { + static ref RE_DURATION: regex::Regex = regex::Regex::new(r"^(?[+-])?P((?P\d+)W)?((?P\d+)D)?(T((?P\d+)H)?((?P\d+)M)?((?P\d+)S)?)?$").unwrap(); +} +use anyhow::{anyhow, Result}; +use chrono::{Duration, NaiveDateTime}; + +pub fn parse_duration(string: &str) -> Result { + let captures = RE_DURATION + .captures(string) + .ok_or(anyhow!("invalid duration format"))?; + + let mut duration = Duration::zero(); + if let Some(weeks) = captures.name("W") { + duration = duration + Duration::weeks(weeks.as_str().parse()?); + } + if let Some(days) = captures.name("D") { + duration = duration + Duration::days(days.as_str().parse()?); + } + if let Some(hours) = captures.name("H") { + duration = duration + Duration::hours(hours.as_str().parse()?); + } + if let Some(minutes) = captures.name("M") { + duration = duration + Duration::minutes(minutes.as_str().parse()?); + } + if let Some(seconds) = captures.name("S") { + duration = duration + Duration::seconds(seconds.as_str().parse()?); + } + if let Some(sign) = captures.name("sign") { + if sign.as_str() == "-" { + duration = -duration; + } + } + + Ok(duration) +} + +#[test] +pub fn test_parse_duration() { + assert_eq!(parse_duration("P12W").unwrap(), Duration::weeks(12)); + assert_eq!(parse_duration("P12D").unwrap(), Duration::days(12)); + assert_eq!(parse_duration("PT12H").unwrap(), Duration::hours(12)); + assert_eq!(parse_duration("PT12M").unwrap(), Duration::minutes(12)); + assert_eq!(parse_duration("PT12S").unwrap(), Duration::seconds(12)); +} + +pub fn parse_datetime(string: &str) -> Result { + // TODO: respect timezones + // + // Format: ^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(?PZ)?$ + // if Z? + // UTC time + // else + // if TZID given? + // time in TZ + // else + // local time of attendee (can be different actual times for different attendees) + // BUT for this implementation will be UTC for now since this case is annoying + // (sabre-dav does same) + let (datetime, _tz_remainder) = NaiveDateTime::parse_and_remainder(string, "%Y%m%dT%H%M%S")?; + Ok(datetime) +} + +#[test] +fn test_parse_datetime() { + dbg!(parse_datetime("19960329T133000Z").unwrap()); +}