aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Pollan2018-08-28 16:48:59 +0200
committerRuben Pollan2018-08-28 16:48:59 +0200
commit6263be67208f68a8c8ce1a8a18fc9921df53048e (patch)
tree47da1c49686d16d06ae77743a50981aad7746dce
parent5eb5bb17c0f7e93aacc340ce9a28ee352cc91c59 (diff)
Get a range of dates
-rw-r--r--src/calendar.rs (renamed from src/events.rs)54
-rw-r--r--src/event.rs27
-rw-r--r--src/main.rs15
-rw-r--r--src/periodic.rs45
4 files changed, 124 insertions, 17 deletions
diff --git a/src/events.rs b/src/calendar.rs
index b0111e7..c49e747 100644
--- a/src/events.rs
+++ b/src/calendar.rs
@@ -1,18 +1,19 @@
use std::io::BufRead;
use std::fmt;
use ical::IcalParser;
+use chrono::Duration;
use date::Date;
-use event::Event;
+use event::{Event, End};
use periodic::Periodic;
use errors::EventError;
-pub struct Events {
+pub struct Calendar {
single: Vec<Event>,
periodic: Vec<Periodic>,
}
-impl Events {
+impl Calendar {
pub fn parse<B: BufRead>(buf: B) -> Result<Self, EventError> {
let reader = IcalParser::new(buf);
let mut single = Vec::new();
@@ -40,7 +41,8 @@ impl Events {
"DESCRIPTION" => event.description = value,
"STATUS" => event.status = value.parse()?,
"DTSTART" => event.start = Date::parse(&value, &time_zone)?,
- "DTEND" => event.end = Date::parse(&value, &time_zone)?,
+ "DTEND" => event.end = End::Date(Date::parse(&value, &time_zone)?),
+ "DURATION" => event.end = End::Duration(duration(&value)?),
"RRULE" => maybe_periodic = Some(rrule(&value, &params)?),
_ => (),
};
@@ -55,12 +57,22 @@ impl Events {
}
}
- single.sort_by(|a, b| a.start.cmp(&b.start));
- Ok(Events { single, periodic })
+ single.sort_by_key(|k| k.start);
+ Ok(Calendar { single, periodic })
+ }
+
+ pub fn get(&self, first: &Date, last: &Date) -> Vec<Event> {
+ // TODO: not all single, just the one by date
+ let mut events = self.single.clone();
+ for p in &self.periodic {
+ events.append(&mut p.get(first, last));
+ }
+ events.sort_by_key(|k| k.start);
+ events
}
}
-impl fmt::Display for Events {
+impl fmt::Display for Calendar {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for event in &self.single {
writeln!(f, "{}", event)?;
@@ -73,7 +85,7 @@ impl fmt::Display for Events {
}
}
-fn rrule(value: &String, params: &Vec<(String, Vec<String>)>) -> Result<Periodic, EventError> {
+fn rrule(value: &str, params: &Vec<(String, Vec<String>)>) -> Result<Periodic, EventError> {
let mut periodic = Periodic::new();
for entry in value.split(";") {
@@ -91,3 +103,29 @@ fn rrule(value: &String, params: &Vec<(String, Vec<String>)>) -> Result<Periodic
Ok(periodic)
}
+
+fn duration(value: &str) -> Result<Duration, EventError> {
+ let mut duration = Duration::seconds(0);
+ let mut acc = "".to_string();
+ for c in value.chars() {
+ match c {
+ '0'...'9' => acc.push(c),
+ '-' => duration = -duration,
+ 'W' | 'H' | 'M' | 'S' | 'D' => {
+ let count = acc.parse()?;
+ acc = "".to_string();
+ let d = match c {
+ 'W' => Duration::weeks(count),
+ 'H' => Duration::hours(count),
+ 'M' => Duration::minutes(count),
+ 'S' => Duration::seconds(count),
+ 'D' => Duration::days(count),
+ _ => Duration::seconds(0),
+ };
+ duration = duration + d;
+ }
+ _ => (),
+ }
+ }
+ Ok(Duration::weeks(1))
+}
diff --git a/src/event.rs b/src/event.rs
index 904b718..b54c422 100644
--- a/src/event.rs
+++ b/src/event.rs
@@ -1,6 +1,8 @@
use std::fmt;
use std::str::FromStr;
+use chrono::Duration;
+
use date::Date;
use errors::EventError;
@@ -8,7 +10,7 @@ use errors::EventError;
#[derive(Debug, Clone)]
pub struct Event {
pub start: Date,
- pub end: Date,
+ pub end: End,
pub summary: String,
pub location: String,
pub description: String,
@@ -22,6 +24,12 @@ pub enum Status {
Canceled,
}
+#[derive(Debug, Copy, Clone)]
+pub enum End {
+ Date(Date),
+ Duration(Duration),
+}
+
impl Event {
pub fn new() -> Event {
@@ -31,14 +39,27 @@ impl Event {
description: "".to_string(),
status: Status::Confirmed,
start: Date::empty(),
- end: Date::empty(),
+ end: End::Date(Date::empty()),
};
}
+
+ pub fn end_date(&self) -> Date {
+ match self.end {
+ End::Date(date) => date,
+ End::Duration(duration) => self.start + duration,
+ }
+ }
}
impl fmt::Display for Event {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{:?}: {}", self.start, self.summary)?;
+ write!(
+ f,
+ "{:?}-{:?}: {}",
+ self.start,
+ self.end_date(),
+ self.summary
+ )?;
if !self.location.is_empty() {
write!(f, " ({})", self.location)?;
}
diff --git a/src/main.rs b/src/main.rs
index 022b811..66e1df1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,18 +5,25 @@ extern crate chrono_tz;
mod date;
mod event;
mod periodic;
-mod events;
+mod calendar;
mod errors;
use std::env;
use std::io::BufReader;
use std::fs::File;
-use events::Events;
+use chrono::Duration;
+use date::Date;
+use calendar::Calendar;
fn main() {
let args: Vec<_> = env::args().collect();
let file = File::open(&args[1]).unwrap();
let buf = BufReader::new(file);
- let events = Events::parse(buf).unwrap();
- println!("{}", events);
+ let calendar = Calendar::parse(buf).unwrap();
+ println!("{}", calendar);
+ println!("");
+
+ let now = Date::now();
+ let events = calendar.get(&now, &(now + Duration::weeks(10)));
+ println!("{:?}", events);
}
diff --git a/src/periodic.rs b/src/periodic.rs
index e46a13b..f6cd2d7 100644
--- a/src/periodic.rs
+++ b/src/periodic.rs
@@ -1,7 +1,10 @@
use std::fmt;
use std::str::FromStr;
-use event::Event;
+use chrono::Duration;
+
+use date::Date;
+use event::{Event, End};
use errors::EventError;
#[derive(Debug)]
@@ -9,7 +12,8 @@ pub struct Periodic {
pub event: Event,
pub freq: Freq,
pub interval: i64,
- // TODO: until, count, ...
+ pub until: Date,
+ // TODO: count, ...
}
#[derive(Debug)]
@@ -29,6 +33,7 @@ impl Periodic {
event: Event::new(),
freq: Freq::Secondly,
interval: 1,
+ until: Date::empty(),
}
}
@@ -36,10 +41,32 @@ impl Periodic {
match param {
"FREQ" => self.freq = value.parse()?,
"INTERVAL" => self.interval = value.parse()?,
+ "UNTIL" => self.until = Date::parse(&value, "")?,
_ => (),
}
Ok(())
}
+
+ pub fn get(&self, first: &Date, last: &Date) -> Vec<Event> {
+ let mut start = self.event.start;
+ let mut end = self.event.end_date();
+ let mut events = Vec::new();
+ while start <= *last {
+ if !self.until.is_empty() && start <= self.until {
+ break;
+ }
+
+ if start >= *first {
+ let mut e = self.event.clone();
+ e.start = start;
+ e.end = End::Date(end);
+ events.push(e);
+ }
+ start = start + self.freq.duration(self.interval);
+ end = end + self.freq.duration(self.interval);
+ }
+ events
+ }
}
impl fmt::Display for Periodic {
@@ -53,6 +80,20 @@ impl fmt::Display for Periodic {
}
}
+impl Freq {
+ pub fn duration(&self, count: i64) -> Duration {
+ match self {
+ Freq::Secondly => Duration::seconds(count),
+ Freq::Minutely => Duration::minutes(count),
+ Freq::Hourly => Duration::hours(count),
+ Freq::Daily => Duration::days(count),
+ Freq::Weekly => Duration::weeks(count),
+ Freq::Monthly => Duration::days(count * 30), // FIXME
+ Freq::Yearly => Duration::days(count * 365), // FIXME
+ }
+ }
+}
+
impl FromStr for Freq {
type Err = EventError;