aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuben Pollan2021-09-29 20:38:30 +0200
committerRuben Pollan2021-09-29 20:38:30 +0200
commit4116776e1d78568febf98b183738ae82263f01eb (patch)
tree166d8ebd08492c3141b8c3d5f4035f4ef467adbd
parenta66cfcac58ae8c9662776741d9727dfb6585fbcc (diff)
Add support to BYDAY in MONTHLY frequency
-rw-r--r--src/date.rs20
-rw-r--r--src/periodic.rs45
2 files changed, 55 insertions, 10 deletions
diff --git a/src/date.rs b/src/date.rs
index 71e29c7..c3cf816 100644
--- a/src/date.rs
+++ b/src/date.rs
@@ -79,6 +79,13 @@ impl Date {
}
}
+ pub fn with_day(&self, day: u32) -> Option<Date> {
+ Some(match *self {
+ Date::Time(t) => Date::Time(t.with_day(day)?),
+ Date::AllDay(d) => Date::AllDay(d.with_day(day)?),
+ })
+ }
+
pub fn weekday(&self) -> Weekday {
match *self {
Date::Time(t) => t.weekday(),
@@ -100,6 +107,12 @@ impl Date {
})
}
+ pub fn week_of_month(&self) -> (i32, i32) {
+ let week = ((self.day() - 1) / 7 + 1) as i32;
+ let neg_week = ((self.days_in_month() - self.day()) / 7 + 1) as i32;
+ (week, -neg_week)
+ }
+
pub fn year(&self) -> i32 {
match *self {
Date::Time(t) => t.year(),
@@ -113,6 +126,13 @@ impl Date {
Date::AllDay(d) => Date::AllDay(d.with_year(year)?),
})
}
+
+ pub fn days_in_month(&self) -> u32 {
+ chrono::NaiveDate::from_ymd_opt(self.year(), self.month() + 1, 1)
+ .unwrap_or(chrono::NaiveDate::from_ymd(self.year() + 1, 1, 1))
+ .pred()
+ .day()
+ }
}
impl Ord for Date {
diff --git a/src/periodic.rs b/src/periodic.rs
index 19874e4..c0d0ad3 100644
--- a/src/periodic.rs
+++ b/src/periodic.rs
@@ -1,5 +1,6 @@
use std::fmt;
use std::str::FromStr;
+use std::ops::Add;
use std::collections::HashMap;
use chrono::{Duration, Weekday};
@@ -129,16 +130,40 @@ impl<'a> Iter<'a> {
}
}
Freq::Monthly => {
- // TODO: byday...
- let new_date = if date.month() == 12 {
- date.with_month(1)
- .unwrap()
- .with_year(date.year() + 1)
- .unwrap()
- } else {
- date.with_month(date.month() + 1).unwrap()
- };
- new_date - date
+ match &p.byday {
+ Some(byday) => {
+ let mut next = date;
+ if p.interval > 1 {
+ for _ in 1..p.interval {
+ next = next.add(Duration::days(next.days_in_month().into()));
+ }
+ }
+ loop {
+ next = next.add(Duration::days(1));
+ let (week, neg_week) = next.week_of_month();
+
+ match byday.get(&next.weekday()) {
+ Some(occurrences) =>
+ if occurrences.contains(&0) || occurrences.contains(&week) ||occurrences.contains(&neg_week) {
+ break;
+ }
+ None => {}
+ };
+ };
+ next - date
+ }
+ None => {
+ let new_date = if date.month() == 12 {
+ date.with_month(1)
+ .unwrap()
+ .with_year(date.year() + 1)
+ .unwrap()
+ } else {
+ date.with_month(date.month() + 1).unwrap()
+ };
+ new_date - date
+ }
+ }
}
// TODO: byday...
Freq::Yearly => date.with_year(date.year() + 1).unwrap() - date,