rrule 0.9.2

A pure Rust implementation of recurrence rules as defined in the iCalendar RFC.
Documentation

A performant rust implementation of recurrence rules as defined in the iCalendar RFC.

This crate provides [RRuleSet] for working with recurrence rules. It has a collection of DTSTART, RRULEs, EXRULEs, RDATEs and EXDATEs. Both the RRULE and EXRULE properties are represented by the [RRule] type and the DTSTART, RDATE and EXDATE properties are represented by the [chrono::DateTime<Tz>].

Building RRule and RRuleSet

[RRuleSet] implements the [std::str::FromStr] trait so that it can be parsed and built from a string representation. [RRuleSet] can also be built by composing multiple [RRule]s for its rrule and exrule properties and [chrono::DateTime<Tz>] for its dt_start, exdate and rdate properties. See the examples below.

use chrono::{DateTime, TimeZone};
use chrono_tz::UTC;
use rrule::{RRuleSet, RRule};

// Parse a RRuleSet string
let rrule_set: RRuleSet = "DTSTART:20120201T023000Z\n\
RRULE:FREQ=MONTHLY;COUNT=5\n\
RDATE:20120701T023000Z,20120702T023000Z\n\
EXRULE:FREQ=MONTHLY;COUNT=2\n\
EXDATE:20120601T023000Z".parse().unwrap();

assert_eq!(*rrule_set.get_dt_start(), UTC.ymd(2012, 2, 1).and_hms(2, 30, 0));
assert_eq!(rrule_set.get_rrule().len(), 1);
assert_eq!(rrule_set.get_exrule().len(), 1);
assert_eq!(rrule_set.get_rdate().len(), 2);
assert_eq!(rrule_set.get_exdate().len(), 1);

Generating occurrences

You can loop over the occurrences of a [RRuleSet] by calling any of the following methods:

  • [RRuleSet::all]: Generate all recurrences that match the rules (with a limit to prevent infinite loops).
  • [RRuleSet::all_between]: Generate all recurrences that match the rules and are between two given dates.
  • [RRuleSet::just_before]: Generate the last recurrence that matches the rules and is before a given date.
  • [RRuleSet::just_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 infinite recurrence rules [RRuleSet] implements the Iterator trait which makes them very flexible. All the methods above uses the iterator trait in its implementation as shown below.

use chrono::{DateTime, TimeZone};
use chrono_tz::UTC;
use rrule::RRuleSet;

let rrule: RRuleSet = "DTSTART:20120201T093000Z\nRRULE:FREQ=DAILY;COUNT=3".parse().unwrap();

// All dates
assert_eq!(
vec![
DateTime::parse_from_rfc3339("2012-02-01T09:30:00+00:00").unwrap(),
DateTime::parse_from_rfc3339("2012-02-02T09:30:00+00:00").unwrap(),
DateTime::parse_from_rfc3339("2012-02-03T09:30:00+00:00").unwrap(),
],
rrule.all(100).unwrap()
);

Find all events that are within a given range.

# use chrono::{DateTime, TimeZone};
# use chrono_tz::UTC;
# use rrule::RRuleSet;
#
let rrule: RRuleSet = "DTSTART:20120201T093000Z\nRRULE:FREQ=DAILY;COUNT=3".parse().unwrap();
// 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 inclusive = true; // Whether dates equal to after or before should be included in the result

assert_eq!(
vec![
DateTime::parse_from_rfc3339("2012-02-02T09:30:00+00:00").unwrap(),
DateTime::parse_from_rfc3339("2012-02-03T09:30:00+00:00").unwrap(),
],
rrule.all_between(after, before, inclusive).unwrap()
);

Note: All the generated recurrence will be in the same time zone as the dt_start property.