use chrono::Timelike; use chrono::{NaiveDate, NaiveTime}; pub static DATE_FORMAT: &str = "%d/%m/%Y"; #[derive(Debug, Clone)] pub struct Event { pub date: NaiveDate, pub start: Option, pub end: Option, pub name: String, } impl Event { pub fn pprint(&self) -> String { let start = self.start.map(pprint_time).unwrap_or_default(); let end = self .end .map(|t| format!("-{}", pprint_time(t))) .unwrap_or_default(); let space = if self.start.is_some() || self.end.is_some() { " " } else { "" }; format!("{}{}{}{}", start, end, space, self.name) } } fn pprint_time(t: NaiveTime) -> String { if t.minute() == 0 { format!("{}h", t.hour()) } else { format!("{}h{}", t.hour(), t.minute()) } } fn parse_time(t: &str) -> Option { match t.split('h').collect::>()[..] { [hours, minutes] => { if minutes.trim().is_empty() { NaiveTime::from_hms_opt(hours.parse().ok()?, 0, 0) } else { NaiveTime::from_hms_opt(hours.parse().ok()?, minutes.parse().ok()?, 0) } } _ => None, } } // Validation pub fn validate(date: String, name: String, start: String, end: String) -> Option { let start = validate_time(start)?; let end = validate_time(end)?; match (start, end) { (Some(s), Some(e)) if s > e => None?, _ => (), } Some(Event { date: NaiveDate::parse_from_str(&date, DATE_FORMAT).ok()?, name: validate_name(name)?, start, end, }) } fn validate_time(time: String) -> Option> { let time = time.trim(); if time.is_empty() { Some(None) } else { parse_time(time).map(|t| Some(t)) } } fn validate_name(name: String) -> Option { let name = name.trim(); if name.is_empty() { None } else { Some(name.to_string()) } }