1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
use chrono::{Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone};
use std::collections::HashMap;
use uuid::Uuid;
use crate::model::repetition::Repetition;
use crate::model::time;
use crate::validation;
pub static DATE_FORMAT: &str = "%d/%m/%Y";
#[derive(Debug, Clone)]
pub struct Event {
pub id: Uuid,
pub date: NaiveDate,
pub start: Option<NaiveTime>,
pub end: Option<NaiveTime>,
pub name: String,
pub repetition: Option<Repetition>,
pub category: Option<Uuid>,
}
impl Event {
pub fn pprint(&self) -> String {
let start = self.start.map(time::pprint).unwrap_or_default();
let end = self
.end
.map(|t| format!("-{}", time::pprint(t)))
.unwrap_or_default();
let space = if self.start.is_some() || self.end.is_some() {
" "
} else {
""
};
format!("{}{}{}{}", start, end, space, self.name)
}
pub fn local_timestamp(&self) -> Option<i64> {
let time = self.start.unwrap_or(NaiveTime::from_hms_opt(0, 0, 0)?);
let naive_datetime = NaiveDateTime::new(self.date, time);
let local_datetime = Local.from_local_datetime(&naive_datetime).single()?;
Some(local_datetime.timestamp())
}
}
/// Recurring events in an date range (inclusive)
pub fn repetitions_between(
events: &[Event],
start: NaiveDate,
end: NaiveDate,
) -> HashMap<NaiveDate, Vec<Event>> {
let mut res: HashMap<NaiveDate, Vec<Event>> = HashMap::new();
for event in events {
if let Some(repetition) = &event.repetition {
for date in repetition.between(event.date, start, end) {
res.entry(date).or_default().push(event.clone())
}
}
}
res
}
// Validation
pub fn validate(
id: Uuid,
date: String,
name: String,
start: String,
end: String,
repetition: Option<Repetition>,
category: Option<Uuid>,
) -> Option<Event> {
let start = validation::time(start)?;
let end = validation::time(end)?;
match (start, end) {
(Some(s), Some(e)) if s > e => None?,
_ => (),
}
Some(Event {
id,
date: NaiveDate::parse_from_str(&date, DATE_FORMAT).ok()?,
name: validation::non_empty(name)?,
start,
end,
repetition,
category,
})
}
|