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
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
//! A performant rust implementation of recurrence rules as defined in the iCalendar RFC.
//!
//! RRule provides two types for working with recurrence rules:
//! - `RRule`: For working with a single recurrence rule without any exception dates (exdates / exrules) and no additonal dates (rdate).
//! - `RRuleSet`: For working with a collection of rrules, exrules, rdates and exdates. Both the rrule and exrule
//! properties are represented by the `RRule` type and the rdate and exdate properties are represented by the DateTime<Tz> type
//! provided by the [chrono](https://crates.io/crates/chrono) and [chrono-tz](https://crates.io/crates/chrono-tz) crates.
//!
//! # Building RRule and RRuleSet
//! Both types implements the `std::str::FromStr` trait so that they can be parsed and built from a string representation. `RRule`
//! can additionally be constructured from the `Option` type which help build the recurrence rule. `RRuleSet`
//! can also be built by composing mutliple `RRule`s for its rrule and exrule properties and DateTime<Tz> for its
//! exdate and rdate properties. See the examples below.
//!
//! # Generating occurences
//! `RRule` and `RRuleSet` have four quick start methods for "querying" for recurrences:
//! - `all`: Generate all recurrences that matches the rules
//! - `between`: Generate all recurrences that matches the rules and are between two given dates
//! - `before`: Generate the last recurrence that matches the rules and is before a given date
//! - `after`: Generate the first recurrence that matches the rules and is after a given date
//!
//! If you have some additional filters or want to work with inifite recurrence rules
//! both `RRule` and `RRuleSet` implements the `Iterator` traits which makes them very flexible.
//! All the methods above uses the iterator trait in its implementation as shown below.
//! ````
//! extern crate rrule;
//! extern crate chrono;
//! extern crate chrono_tz;
//!
//! use chrono::prelude::*;
//! use chrono_tz::UTC;
//! use rrule::RRule;
//!
//! let mut rrule: RRule = "DTSTART:20120201T093000Z\nRRULE:FREQ=DAILY;COUNT=3".parse().unwrap();
//!
//!
//! // All dates
//! let all_occurences: Vec<_> = rrule.clone().into_iter().collect();
//! assert_eq!(all_occurences, rrule.all());
//!
//! // Between two dates
//! let after = UTC.ymd(2012, 2, 1).and_hms(10, 0, 0);
//! let before = UTC.ymd(2012, 4, 1).and_hms(9, 0, 0);
//! let inc = true; // Wheter dates equal to after or before should be added;
//!
//! let occurences_between_dates: Vec<_> = rrule.clone()
//!     .into_iter()
//!     .skip_while(|d| if inc { *d <= after } else { *d < after })
//!     .take_while(|d| if inc { *d <= before } else { *d < before })
//!     .collect();
//! assert_eq!(occurences_between_dates, rrule.between(after, before, inc));
//!
//!
//! // After a date
//! let after = UTC.ymd(2012, 2, 1).and_hms(10, 0, 0);
//! let inc = true; // Wheter dates equals to after should be added;
//!
//! let occurences_after_date = rrule.clone()
//!     .into_iter()
//!     .skip_while(|d| if inc { *d <= after } else { *d < after })
//!     .next();
//! assert_eq!(occurences_after_date, rrule.after(after, inc));
//!
//!
//! // Before a date
//! let before = UTC.ymd(2012, 4, 1).and_hms(10, 0, 0);
//! let inc = true; // Wheter dates equals to before should be added;
//!
//! let occurences_before_date = rrule.clone()
//!     .into_iter()
//!     .take_while(|d| if inc { *d <= before } else { *d < before })
//!     .last();
//! assert_eq!(occurences_before_date, rrule.before(before, inc));
//!
//! ````
//!
//! Note: All the generated recurrence will be in the same time zone as the dtstart property.
//!
//! # Examples
//!
//! Quick start by parsing strings
//!
//! ```
//! extern crate rrule;
//!
//! use rrule::RRule;
//!
//! // Parse a RRule string
//! let mut rrule: RRule = "DTSTART:20120201T093000Z\nRRULE:FREQ=WEEKLY;INTERVAL=5;UNTIL=20130130T230000Z;BYDAY=MO,FR".parse().unwrap();
//! assert_eq!(rrule.all().len(), 21);
//!
//!
//! use rrule::RRuleSet;
//!
//! // Parse a RRuleSet string
//! let mut rrule_set: RRuleSet = "DTSTART:20120201T023000Z\nRRULE:FREQ=MONTHLY;COUNT=5\nRDATE:20120701T023000Z,20120702T023000Z\nEXRULE:FREQ=MONTHLY;COUNT=2\nEXDATE:20120601T023000Z".parse().unwrap();
//! assert_eq!(rrule_set.all().len(), 4);
//! ```
//!
//!
//!
//! Using `Options` to build RRule
//!
//! ```
//! extern crate rrule;
//! extern crate chrono;
//! extern crate chrono_tz;
//!
//! use chrono::prelude::*;
//! use chrono_tz::UTC;
//! use rrule::{RRule, Options, Frequenzy, Weekday};
//!
//! // Build options that starts first day in 2020 at 9:00AM and occurs daily 5 times
//! let mut options = Options::new()
//!     .dtstart(UTC.ymd(2020, 1, 1).and_hms(9, 0, 0))
//!     .count(5)
//!     .freq(Frequenzy::Daily)
//!     .build()
//!     .unwrap();
//!
//! // Construct `RRule` from options
//! let mut rrule = RRule::new(options);
//! let recurrences = rrule.all();
//! for i in 0..5 {
//!     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!(recurrences.len(), 5);
//! ```
//!
//!
//! 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 recurrences on Wednesday only.
//! ```
//! extern crate rrule;
//! extern crate chrono;
//! extern crate chrono_tz;
//!
//! use chrono::prelude::*;
//! use chrono_tz::UTC;
//! use rrule::{RRule, RRuleSet, Options, Frequenzy, Weekday};
//!
//!
//! // Build options for rrule that occurs weekly on Tuesday and Wednesday
//! let mut rrule_options = Options::new()
//!     .dtstart(UTC.ymd(2020, 1, 1).and_hms(9, 0, 0))
//!     .count(4)
//!     .freq(Frequenzy::Weekly)
//!     .byweekday(vec![Weekday::Tue, Weekday::Wed])
//!     .build()
//!     .unwrap();
//!
//! // Construct `RRule` from options
//! let mut rrule = RRule::new(rrule_options);
//!
//!
//! // Build options for exrule that occurs weekly on Wednesday
//! let mut exrule_options = Options::new()
//!     .dtstart(UTC.ymd(2020, 1, 1).and_hms(9, 0, 0))
//!     .count(4)
//!     .freq(Frequenzy::Weekly)
//!     .byweekday(vec![Weekday::Wed])
//!     .build()
//!     .unwrap();
//!
//! // Construct `RRule` from options
//! let mut exrule = RRule::new(exrule_options);
//!
//! // Now create the RRuleSet and add rrule and exrule
//! let mut rrule_set = RRuleSet::new();
//! rrule_set.rrule(rrule);
//! rrule_set.exrule(exrule);
//!
//! let recurrences = rrule_set.all();
//!
//! // Check that all the recurrences are on a Tuesday
//! for occurence in &recurrences {
//!     assert_eq!(occurence.weekday(), Weekday::Tue);
//! }
//!
//! assert_eq!(recurrences.len(), 2);
//! ```
//!
//!
//!
//!
//! Timezone support.
//! The following examples uses `RRuleSet` with one `RRule` that yields recurrences
//! in the Europe/Berlin timezone, and one EXDATE that is specified
//! in UTC and collides with one of those recurrences.  
//! ```
//! extern crate rrule;
//! extern crate chrono;
//! extern crate chrono_tz;
//!
//! use chrono::prelude::*;
//! use chrono_tz::{UTC, Tz};
//! use chrono_tz::Europe::Berlin;
//! use rrule::{RRule, RRuleSet, Options, Frequenzy, Weekday};
//!
//!
//!
//! // Build options for rrule that occurs daily at 9 oclock for 4 times
//! let mut rrule_options = Options::new()
//!     .dtstart(Berlin.ymd(2020, 1, 1).and_hms(9, 0, 0))
//!     .count(4)
//!     .freq(Frequenzy::Daily)
//!     .build()
//!     .unwrap();
//!
//! let mut rrule = RRule::new(rrule_options);
//!
//! // Exdate in the UTC at 8 oclock which is 9 oclock in Berlin and therefore
//! // collides with the second rrule occurence.
//! let exdate = UTC.ymd(2020, 1, 2).and_hms(8, 0, 0);
//!
//! // Now create the RRuleSet and add rrule and exdate
//! let mut rrule_set = RRuleSet::new();
//! rrule_set.rrule(rrule);
//! rrule_set.exdate(exdate);
//!
//! 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.
//! // Refer to the chrono and chrono-tz crates for more documenation on working with the DateTime type.
//!
//! // Example of converting to mocow timezone
//! use chrono_tz::Europe::Moscow;
//!
//! 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 recurrences_in_local_tz: Vec<DateTime<Local>> = recurrences.iter()
//!     .map(|d| d.with_timezone(&Local)).collect();
//!
//!
//! ```

extern crate chrono;
extern crate chrono_tz;
extern crate regex;
extern crate serde;
#[macro_use]
extern crate lazy_static;

mod datetime;
mod iter;
mod options;
mod parse_options;
mod rrule;
mod rrule_iter;
mod rruleset;
mod rruleset_iter;
mod rrulestr;
mod utils;

pub use crate::options::{Frequenzy, NWeekday, Options, ParsedOptions};
pub use crate::rrule::RRule;
pub use crate::rruleset::RRuleSet;
pub use chrono::Weekday;