summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFredrik Meringdal <fmeringdal@hotmail.com>2020-11-01 21:22:20 +0100
committerFredrik Meringdal <fmeringdal@hotmail.com>2020-11-01 21:22:20 +0100
commited603b788b23535b086f2a7491627e018e8dce5d (patch)
tree15bda7fde8339ff6b105305f8f1a74c937430b44
parentf923e14ebe037c63f081ea036a9a259c5abd0935 (diff)
downloadrust_rrule-ed603b788b23535b086f2a7491627e018e8dce5d.zip
docs and removed some stuff from options
-rw-r--r--README.md6
-rw-r--r--src/lib.rs36
-rw-r--r--src/options.rs13
-rw-r--r--src/parse_options.rs15
-rw-r--r--src/rrule.rs32
-rw-r--r--src/rruleset.rs43
-rw-r--r--src/rruleset_iter.rs6
-rw-r--r--src/rrulestr.rs9
-rw-r--r--tests/rrule.rs2
9 files changed, 91 insertions, 71 deletions
diff --git a/README.md b/README.md
index b753437..f394759 100644
--- a/README.md
+++ b/README.md
@@ -15,9 +15,9 @@ use rrule::build_rrule;
let mut rrule = build_rrule("DTSTART:20120201T093000Z\nRRULE:FREQ=DAILY;COUNT=3").unwrap();
-// Get all occurrences of the rrule
-let occurences = rrule.all();
-assert_eq!(occurences.len(), 3);
+// Get all recurrences of the rrule
+let recurrences = rrule.all();
+assert_eq!(recurrences.len(), 3);
```
# Documentation and more examples
diff --git a/src/lib.rs b/src/lib.rs
index 00eaaad..6685810 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -52,14 +52,14 @@
//!
//! // Construct `RRule` from options
//! let mut rrule = RRule::new(options);
-//! let occurences = rrule.all();
+//! let recurrences = rrule.all();
//! for i in 0..5 {
-//! assert_eq!(occurences[i].year(), 2020);
-//! assert_eq!(occurences[i].month(), 1);
-//! assert_eq!(occurences[i].day(), 1 + i as u32);
-//! assert_eq!(occurences[i].hour(), 9);
+//! assert_eq!(recurrences[i].year(), 2020);
+//! assert_eq!(recurrences[i].month(), 1);
+//! assert_eq!(recurrences[i].day(), 1 + i as u32);
+//! assert_eq!(recurrences[i].hour(), 9);
//! }
-//! assert_eq!(occurences.len(), 5);
+//! assert_eq!(recurrences.len(), 5);
//!
//!
//!
@@ -68,7 +68,7 @@
//! // Construct RRuleSet from one rrule and exrule
//! // The rrule will occur weekly on Tuesday and Wednesday and the exrule
//! // will occur weekly on Wednesday, and therefore the end result will contain
-//! // weekly occurences just on Wednesday.
+//! // weekly recurrences just on Wednesday.
//!
//!
//! // Build options for rrule that occurs weekly on Tuesday and Wednesday
@@ -101,13 +101,13 @@
//! rrule_set.rrule(rrule);
//! rrule_set.exrule(exrule);
//!
-//! let occurences = rrule_set.all();
+//! let recurrences = rrule_set.all();
//!
-//! for occurence in &occurences {
+//! for occurence in &recurrences {
//! assert_eq!(occurence.weekday(), Weekday::Tue);
//! }
//!
-//! assert_eq!(occurences.len(), 2);
+//! assert_eq!(recurrences.len(), 2);
//! ```
//!
//!
@@ -126,14 +126,14 @@
//! use rrule::{RRule, RRuleSet, Options, Frequenzy, Weekday};
//!
//! // SOME NOTES:
-//! // Occurences produced by an rrule will be in the same timezone
+//! // recurrences produced by an rrule will be in the same timezone
//! // as the start datetime provided (dtstart). The `until` datetime MUST
//! // always be specified with the UTC timezone if it is specified.
//!
//! // Example:
-//! // The following examples uses the RRuleSet type with an RRule that yields occurences
+//! // The following examples uses the RRuleSet type with an RRule that yields recurrences
//! // in the Europe/Berlin timezone, and one EXDATE that is specified
-//! // in UTC and collides (and therefore filters away) with one of those occurences.
+//! // in UTC and collides (and therefore filters away) with one of those recurrences.
//!
//!
//! // Build options for rrule that occurs daily at 9 oclock for 4 times
@@ -155,9 +155,9 @@
//! rrule_set.rrule(rrule);
//! rrule_set.exdate(exdate);
//!
-//! let occurences = rrule_set.all();
-//! // RRule contained 4 occurences but 1 was filtered away by the exdate
-//! assert_eq!(occurences.len(), 3);
+//! let recurrences = rrule_set.all();
+//! // RRule contained 4 recurrences but 1 was filtered away by the exdate
+//! assert_eq!(recurrences.len(), 3);
//!
//! // If you want to get back the DateTimes in another timezone you can just iterate over the result
//! // and convert them to another timezone by using the with_timzone method provided by the DateTime type.
@@ -166,12 +166,12 @@
//! // Example of converting to mocow timezone
//! use chrono_tz::Europe::Moscow;
//!
-//! let occurences_in_moscow_tz: Vec<DateTime<Tz>> = occurences.iter()
+//! let recurrences_in_moscow_tz: Vec<DateTime<Tz>> = recurrences.iter()
//! .map(|d| d.with_timezone(&Moscow)).collect();
//!
//!
//! // Example of converting to local timezone (Local comes from chrono::prelude::*)
-//! let occurences_in_local_tz: Vec<DateTime<Local>> = occurences.iter()
+//! let recurrences_in_local_tz: Vec<DateTime<Local>> = recurrences.iter()
//! .map(|d| d.with_timezone(&Local)).collect();
//!
//!
diff --git a/src/options.rs b/src/options.rs
index 884ecb6..31f884b 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -1,7 +1,7 @@
use crate::datetime::{get_weekday_val, DTime};
use crate::parse_options::parse_options;
use chrono::prelude::*;
-use chrono_tz::Tz;
+use chrono_tz::{Tz, UTC};
use std::error::Error;
use std::fmt::{Display, Formatter};
@@ -39,7 +39,6 @@ pub struct ParsedOptions {
pub byeaster: Option<isize>,
}
-// TODO: PartialOptions shouldnt have all of these fields
#[derive(Debug, Clone)]
pub struct Options {
pub freq: Option<Frequenzy>,
@@ -52,14 +51,12 @@ pub struct Options {
pub bysetpos: Option<Vec<isize>>,
pub bymonth: Option<Vec<usize>>,
pub bymonthday: Option<Vec<isize>>,
- pub bynmonthday: Option<Vec<isize>>,
pub byyearday: Option<Vec<isize>>,
pub byweekno: Option<Vec<isize>>,
pub byweekday: Option<Vec<usize>>,
pub byhour: Option<Vec<usize>>,
pub byminute: Option<Vec<usize>>,
pub bysecond: Option<Vec<usize>>,
- pub bynweekday: Option<Vec<Vec<isize>>>,
pub byeaster: Option<isize>,
}
@@ -76,14 +73,12 @@ impl Options {
bysetpos: None,
bymonth: None,
bymonthday: None,
- bynmonthday: None,
byyearday: None,
byweekno: None,
byweekday: None,
byhour: None,
byminute: None,
bysecond: None,
- bynweekday: None,
byeaster: None,
}
}
@@ -108,14 +103,12 @@ impl Options {
bysetpos: Self::is_some_or_none(&opt1.bysetpos, &opt2.bysetpos).clone(),
bymonth: Self::is_some_or_none(&opt1.bymonth, &opt2.bymonth).clone(),
bymonthday: Self::is_some_or_none(&opt1.bymonthday, &opt2.bymonthday).clone(),
- bynmonthday: Self::is_some_or_none(&opt1.bynmonthday, &opt2.bynmonthday).clone(),
byyearday: Self::is_some_or_none(&opt1.byyearday, &opt2.byyearday).clone(),
byweekno: Self::is_some_or_none(&opt1.byweekno, &opt2.byweekno).clone(),
byweekday: Self::is_some_or_none(&opt1.byweekday, &opt2.byweekday).clone(),
byhour: Self::is_some_or_none(&opt1.byhour, &opt2.byhour).clone(),
byminute: Self::is_some_or_none(&opt1.byminute, &opt2.byminute).clone(),
bysecond: Self::is_some_or_none(&opt1.bysecond, &opt2.bysecond).clone(),
- bynweekday: Self::is_some_or_none(&opt1.bynweekday, &opt2.bynweekday).clone(),
byeaster: Self::is_some_or_none(&opt1.byeaster, &opt2.byeaster).clone(),
}
}
@@ -135,8 +128,8 @@ impl Options {
self
}
- pub fn until(mut self, until: DTime) -> Self {
- self.until = Some(until);
+ pub fn until(mut self, until: DateTime<Utc>) -> Self {
+ self.until = Some(until.with_timezone(&UTC));
self
}
diff --git a/src/parse_options.rs b/src/parse_options.rs
index 727da86..0387e51 100644
--- a/src/parse_options.rs
+++ b/src/parse_options.rs
@@ -15,6 +15,9 @@ pub fn parse_options(options: &Options) -> Result<ParsedOptions, RRuleParseError
UTC
};
+ let mut bynweekday: Vec<Vec<isize>> = vec![];
+ let mut bynmonthday: Vec<isize> = vec![];
+
let mut partial_options = Options::concat(&default_partial_options, options);
if partial_options.byeaster.is_some() {
@@ -72,10 +75,9 @@ pub fn parse_options(options: &Options) -> Result<ParsedOptions, RRuleParseError
}
match &partial_options.bymonthday {
- None => partial_options.bynmonthday = None,
+ None => bynmonthday = vec![],
Some(opts_bymonthday) => {
let mut bymonthday = vec![];
- let mut bynmonthday = vec![];
for v in opts_bymonthday {
if *v > 0 {
@@ -86,13 +88,12 @@ pub fn parse_options(options: &Options) -> Result<ParsedOptions, RRuleParseError
}
partial_options.bymonthday = Some(bymonthday);
- partial_options.bynmonthday = Some(bynmonthday);
}
}
- // byweekday / bynweekday
+ // byweekday / bynweekday // ! more to do here
if partial_options.byweekday.is_some() {
- partial_options.bynweekday = None;
+ // partial_options.bynweekday = None;
}
// byhour
@@ -121,14 +122,14 @@ pub fn parse_options(options: &Options) -> Result<ParsedOptions, RRuleParseError
bysetpos: partial_options.bysetpos.unwrap_or(vec![]),
bymonth: partial_options.bymonth.unwrap_or(vec![]),
bymonthday: partial_options.bymonthday.unwrap_or(vec![]),
- bynmonthday: partial_options.bynmonthday.unwrap_or(vec![]),
+ bynmonthday,
byyearday: partial_options.byyearday.unwrap_or(vec![]),
byweekno: partial_options.byweekno.unwrap_or(vec![]),
byweekday: partial_options.byweekday.unwrap_or(vec![]),
byhour: partial_options.byhour.unwrap_or(vec![]),
byminute: partial_options.byminute.unwrap_or(vec![]),
bysecond: partial_options.bysecond.unwrap_or(vec![]),
- bynweekday: partial_options.bynweekday.unwrap_or(vec![]),
+ bynweekday,
byeaster: partial_options.byeaster,
})
}
diff --git a/src/rrule.rs b/src/rrule.rs
index 5083161..68f77ad 100644
--- a/src/rrule.rs
+++ b/src/rrule.rs
@@ -14,6 +14,7 @@ impl RRule {
Self { options }
}
+ /// Returns all the recurrences of the rrule
pub fn all(&mut self) -> Vec<DateTime<Tz>> {
let iter_args = IterArgs {
inc: true,
@@ -26,8 +27,11 @@ impl RRule {
let res = iter(&mut iter_res, &mut self.options);
res
}
-
- pub fn before(&mut self, dt: DateTime<Tz>, inc: bool) -> Vec<DateTime<Tz>> {
+
+ /// Returns the last recurrence before the given datetime instance.
+ /// The inc keyword defines what happens if dt is an recurrence.
+ /// With inc == true, if dt itself is an recurrence, it will be returned.
+ pub fn before(&mut self, dt: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
let iter_args = IterArgs {
inc,
before: None,
@@ -36,10 +40,18 @@ impl RRule {
};
let mut iter_res = RRuleIterRes::new(QueryMethodTypes::Before, iter_args);
- iter(&mut iter_res, &mut self.options)
+ let recurrences = iter(&mut iter_res, &mut self.options);
+ if recurrences.is_empty() {
+ None
+ } else {
+ Some(recurrences[0])
+ }
}
- pub fn after(&mut self, dt: DateTime<Tz>, inc: bool) -> Vec<DateTime<Tz>> {
+ /// Returns the last recurrence after the given datetime instance.
+ /// The inc keyword defines what happens if dt is an recurrence.
+ /// With inc == true, if dt itself is an recurrence, it will be returned.
+ pub fn after(&mut self, dt: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
let iter_args = IterArgs {
inc,
before: None,
@@ -47,10 +59,18 @@ impl RRule {
dt: Some(dt),
};
let mut iter_res = RRuleIterRes::new(QueryMethodTypes::After, iter_args);
-
- iter(&mut iter_res, &mut self.options)
+ let recurrences = iter(&mut iter_res, &mut self.options);
+ if recurrences.is_empty() {
+ None
+ } else {
+ Some(recurrences[0])
+ }
}
+ /// Returns all the recurrences of the rrule between after and before.
+ /// The inc keyword defines what happens if after and/or before are
+ /// themselves recurrences. With inc == true, they will be included in the
+ /// list, if they are found in the recurrence set.
pub fn between(
&mut self,
after: DateTime<Tz>,
diff --git a/src/rruleset.rs b/src/rruleset.rs
index 4a3caa5..4bea086 100644
--- a/src/rruleset.rs
+++ b/src/rruleset.rs
@@ -40,30 +40,41 @@ impl RRuleSet {
self.exdate.push(exdate);
}
+ /// Returns all the recurrences of the rruleset
pub fn all(&mut self) -> Vec<DateTime<Tz>> {
let mut iter = RRuleSetIter::all(self);
iter.iter()
}
/// Returns the last recurrence before the given datetime instance.
- /// The inc keyword defines what happens if dt is an occurrence.
- /// With inc == true, if dt itself is an occurrence, it will be returned.
- pub fn before(&mut self, date: DateTime<Tz>, inc: bool) -> Vec<DateTime<Tz>> {
+ /// The inc keyword defines what happens if dt is an recurrence.
+ /// With inc == true, if dt itself is an recurrence, it will be returned.
+ pub fn before(&mut self, date: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
let mut iter = RRuleSetIter::before(self, date, inc);
- iter.iter()
+ let recurrences = iter.iter();
+ if recurrences.is_empty() {
+ None
+ } else {
+ Some(recurrences[0])
+ }
}
/// Returns the last recurrence after the given datetime instance.
- /// The inc keyword defines what happens if dt is an occurrence.
- /// With inc == true, if dt itself is an occurrence, it will be returned.
- pub fn after(&mut self, date: DateTime<Tz>, inc: bool) -> Vec<DateTime<Tz>> {
+ /// The inc keyword defines what happens if dt is an recurrence.
+ /// With inc == true, if dt itself is an recurrence, it will be returned.
+ pub fn after(&mut self, date: DateTime<Tz>, inc: bool) -> Option<DateTime<Tz>> {
let mut iter = RRuleSetIter::after(self, date, inc);
- iter.iter()
+ let recurrences = iter.iter();
+ if recurrences.is_empty() {
+ None
+ } else {
+ Some(recurrences[0])
+ }
}
- /// Returns all the occurrences of the rrule between after and before.
+ /// Returns all the recurrences of the rrule between after and before.
/// The inc keyword defines what happens if after and/or before are
- /// themselves occurrences. With inc == True, they will be included in the
+ /// themselves recurrences. With inc == true, they will be included in the
/// list, if they are found in the recurrence set.
pub fn between(
&mut self,
@@ -396,9 +407,9 @@ mod test_iter_set {
let rrule = RRule::new(options);
set.exrule(rrule);
- test_recurring(
- set.before(ymd_hms_2(2015, 9, 2, 9, 0, 0), false),
- vec![ymd_hms_2(2014, 9, 2, 9, 0, 0)],
+ assert_eq!(
+ set.before(ymd_hms_2(2015, 9, 2, 9, 0, 0), false).unwrap(),
+ ymd_hms_2(2014, 9, 2, 9, 0, 0),
);
}
@@ -454,9 +465,9 @@ mod test_iter_set {
let rrule = RRule::new(options);
set.exrule(rrule);
- test_recurring(
- set.after(ymd_hms_2(2000, 9, 2, 9, 0, 0), false),
- vec![ymd_hms_2(2007, 9, 2, 9, 0, 0)],
+ assert_eq!(
+ set.after(ymd_hms_2(2000, 9, 2, 9, 0, 0), false).unwrap(),
+ ymd_hms_2(2007, 9, 2, 9, 0, 0),
);
}
diff --git a/src/rruleset_iter.rs b/src/rruleset_iter.rs
index 0b3fe35..9cc2c3e 100644
--- a/src/rruleset_iter.rs
+++ b/src/rruleset_iter.rs
@@ -8,7 +8,7 @@ use std::collections::HashMap;
/// Result iterator for the RRuleSet type. It mostly just wraps
/// `RRuleIterRes` and also before accepting any date makes sure that
/// it does not collide with any exdates provided by either the exdates property
-/// or produced by the exrule rules.
+/// or any occurence produced by any of the the exrules.
pub struct RRuleSetIter<'a> {
exdate_hash: HashMap<i64, ()>,
iter_res: RRuleIterRes,
@@ -95,7 +95,7 @@ impl<'a> RRuleSetIter<'a> {
}
}
- /// Here it is required to recompute exrules to see if some of the occurences will collide with the provided date.
+ /// Here it is required to recompute exrules to see if some of the recurrences will collide with the provided date.
fn accept_when_unknown_bounds(&mut self, date: DateTime<Tz>) -> bool {
let dt = date.timestamp();
if !self.exdate_hash.contains_key(&dt) {
@@ -112,7 +112,7 @@ impl<'a> RRuleSetIter<'a> {
true
}
- /// No need to recompute exrules as it has already beeen computed in the start of the iter method
+ /// No need to recompute exrules as it has already been computed in the start of the iter method
/// because the bounds where known.
fn accept_when_known_bounds(&mut self, date: DateTime<Tz>) -> bool {
let dt = date.timestamp();
diff --git a/src/rrulestr.rs b/src/rrulestr.rs
index 20670f8..62a2e29 100644
--- a/src/rrulestr.rs
+++ b/src/rrulestr.rs
@@ -9,23 +9,20 @@ use once_cell::sync::Lazy;
use regex::Regex;
use std::str::FromStr;
+/// Some regex used for parsing the rrule string.
static DATESTR_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)^(\d{4})(\d{2})(\d{2})(T(\d{2})(\d{2})(\d{2})Z?)?$").unwrap());
static DTSTART_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)DTSTART(?:;TZID=([^:=]+?))?(?::|=)([^;\s]+)").unwrap());
-
static RRULE_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^(?:RRULE|EXRULE):").unwrap());
-
static PARSE_LINE_RE_1: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^\s+|\s+$").unwrap());
static PARSE_LINE_RE_2: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^([A-Z]+?)[:;]").unwrap());
-
static RDATE_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)RDATE(?:;TZID=([^:=]+))?").unwrap());
static EXDATE_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)EXDATE(?:;TZID=([^:=]+))?").unwrap());
-
-
static DATETIME_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)(VALUE=DATE(-TIME)?)|(TZID=)").unwrap());
+
fn parse_datestring_bit<T: FromStr>(
bits: &regex::Captures,
i: usize,
@@ -171,7 +168,7 @@ fn parse_rrule(line: &str) -> Result<Options, RRuleParseError> {
options.interval = Some(interval);
}
"BYSETPOS" => {
- let bysetpos = stringval_to_intvec(value, |pos| true, format!("Invalid bysetpos value"))?;
+ let bysetpos = stringval_to_intvec(value, |_pos| true, format!("Invalid bysetpos value"))?;
options.bysetpos = Some(bysetpos);
}
"BYMONTH" => {
diff --git a/tests/rrule.rs b/tests/rrule.rs
index d62ebe3..bfb6f7c 100644
--- a/tests/rrule.rs
+++ b/tests/rrule.rs
@@ -5333,7 +5333,6 @@ mod test {
#[test]
fn minutely_by_yeardayneg() {
- let start = std::time::SystemTime::now();
let options = ParsedOptions {
freq: Frequenzy::Minutely,
count: Some(4),
@@ -6197,7 +6196,6 @@ mod test {
#[test]
fn secondly_by_yeardayneg() {
- let start = std::time::SystemTime::now();
let options = ParsedOptions {
freq: Frequenzy::Secondly,
count: Some(4),