small improvements to timestamp parsing

This commit is contained in:
Lennart
2025-05-02 19:06:56 +02:00
parent 97a5bd581f
commit 32e1ce85f1
3 changed files with 38 additions and 22 deletions

View File

@@ -0,0 +1,25 @@
pub trait IcalProperty {
fn get_param(&self, name: &str) -> Option<Vec<&str>>;
fn get_value_type(&self) -> Option<&str>;
fn get_tzid(&self) -> Option<&str>;
}
impl IcalProperty for ical::property::Property {
fn get_param(&self, name: &str) -> Option<Vec<&str>> {
self.params
.as_ref()?
.iter()
.find(|(key, _)| name == key)
.map(|(_, value)| value.iter().map(String::as_str).collect())
}
fn get_value_type(&self) -> Option<&str> {
self.get_param("VALUE")
.and_then(|params| params.into_iter().next())
}
fn get_tzid(&self) -> Option<&str> {
self.get_param("TZID")
.and_then(|params| params.into_iter().next())
}
}

View File

@@ -1,5 +1,6 @@
mod calendar; mod calendar;
mod event; mod event;
mod ical;
mod journal; mod journal;
mod object; mod object;
mod rrule; mod rrule;
@@ -8,6 +9,7 @@ mod todo;
pub use calendar::*; pub use calendar::*;
pub use event::*; pub use event::*;
pub use ical::*;
pub use journal::*; pub use journal::*;
pub use object::*; pub use object::*;
pub use timestamp::*; pub use timestamp::*;

View File

@@ -3,13 +3,15 @@ use chrono::{DateTime, Duration, NaiveDate, NaiveDateTime, NaiveTime, Utc};
use chrono_tz::Tz; use chrono_tz::Tz;
use derive_more::derive::Deref; use derive_more::derive::Deref;
use ical::{ use ical::{
parser::{ical::component::IcalTimeZone, Component}, parser::{Component, ical::component::IcalTimeZone},
property::Property, property::Property,
}; };
use lazy_static::lazy_static; use lazy_static::lazy_static;
use rustical_xml::{ValueDeserialize, ValueSerialize}; use rustical_xml::{ValueDeserialize, ValueSerialize};
use std::{collections::HashMap, ops::Add}; use std::{collections::HashMap, ops::Add};
use super::IcalProperty;
lazy_static! { lazy_static! {
static ref RE_DURATION: regex::Regex = regex::Regex::new(r"^(?<sign>[+-])?P((?P<W>\d+)W)?((?P<D>\d+)D)?(T((?P<H>\d+)H)?((?P<M>\d+)M)?((?P<S>\d+)S)?)?$").unwrap(); static ref RE_DURATION: regex::Regex = regex::Regex::new(r"^(?<sign>[+-])?P((?P<W>\d+)W)?((?P<D>\d+)D)?(T((?P<H>\d+)H)?((?P<M>\d+)M)?((?P<S>\d+)S)?)?$").unwrap();
@@ -74,24 +76,15 @@ impl CalDateTime {
prop: &Property, prop: &Property,
timezones: &HashMap<String, IcalTimeZone>, timezones: &HashMap<String, IcalTimeZone>,
) -> Result<Option<Self>, Error> { ) -> Result<Option<Self>, Error> {
let prop_value = if let Some(value) = &prop.value { let prop_value = if let Some(value) = prop.value.as_ref() {
value.to_owned() value
} else { } else {
return Ok(None); return Ok(None);
}; };
// Use the TZID parameter from the property // Use the TZID parameter from the property
let timezone = if let Some(tzid) = &prop let timezone = if let Some(tzid) = prop.get_tzid() {
.params if let Some(timezone) = timezones.get(tzid) {
.clone()
.unwrap_or_default()
.iter()
.filter(|(name, _values)| name == "TZID")
.map(|(_name, values)| values.first())
.next()
.unwrap_or_default()
{
if let Some(timezone) = timezones.get(tzid.to_owned()) {
// X-LIC-LOCATION is often used to refer to a standardised timezone from the Olson // X-LIC-LOCATION is often used to refer to a standardised timezone from the Olson
// database // database
if let Some(olson_name) = timezone if let Some(olson_name) = timezone
@@ -109,13 +102,9 @@ impl CalDateTime {
} else { } else {
// If the TZID matches a name from the Olson database (e.g. Europe/Berlin) we // If the TZID matches a name from the Olson database (e.g. Europe/Berlin) we
// guess that we can just use it // guess that we can just use it
if let Ok(tz) = tzid.parse::<Tz>() { tzid.parse::<Tz>().ok()
Some(tz) // TODO: If None: Too bad, we need to manually parse it
} else { // For now it's just treated as localtime
// TODO: Too bad, we need to manually parse it
// For now it's just treated as localtime
None
}
} }
} else { } else {
// TZID refers to timezone that does not exist // TZID refers to timezone that does not exist
@@ -129,7 +118,7 @@ impl CalDateTime {
None None
}; };
Self::parse(&prop_value, timezone).map(Some) Self::parse(prop_value, timezone).map(Some)
} }
pub fn format(&self) -> String { pub fn format(&self) -> String {