Recurring Events
Recurrence rules allow events to recur, for example for a weekly meeting, or
an anniversary. This is done with the RRULE and RDATE property. The RRULE
property allows for a LOT of different rules. VObject has support for a lot of
them, but not all.
To read more about RRULE and all the options, check out RFC5545.
VObject supports the following options:
UNTILfor an end date,INTERVALfor for example "every 2 days",COUNTto stop recurring after x items,FREQ=DAILYto recur every day, andBYDAYto limit it to certain days,FREQ=WEEKLYto recur every week,BYDAYto expand this to multiple weekdays in every week andWKSTto specify on which day the week starts,FREQ=MONTHLYto recur every month,BYMONTHDAYto expand this to certain days in a month,BYDAYto expand it to certain weekdays occurring in a month, andBYSETPOSto limit the last two expansions,FREQ=YEARLYto recur every year,BYMONTHto expand that to certain months in a year, andBYDAYandBYWEEKDAYto expand theBYMONTHrule even further.
VObject supports the EXDATE property for exclusions, and RDATE as well.
This is an example of a meeting that happens every 2nd monday of every month:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Sabre//Sabre VObject 2.0//EN
BEGIN:VEVENT
UID:1102c450-e0d7-11e1-9b23-0800200c9a66
DTSTART:20120109T140000Z
RRULE:FREQ=MONTHLY;BYDAY=MO;BYSETPOS=2
END:VEVENT
END:VCALENDAR
To figure out all the meetings for this year, we can use the following syntax:
$vcalendar = VObject\Reader::read($data);
$newVCalendar = $vcalendar->expand(new DateTime('2012-01-01'), new DateTime('2012-12-31'));
What the expand method does, is look at its inner events, and expand all the recurrence rules. Then, it returns a new calendar that has all its events expanded.
This new calendar now contains 12 events. The first will have its RRULE stripped,
and every subsequent VEVENT has the correct meeting date and a RECURRENCE-ID set.
This results in something like this:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Sabre//Sabre VObject 2.0//EN
BEGIN:VEVENT
UID:1102c450-e0d7-11e1-9b23-0800200c9a66
DTSTART:20120109T140000Z
END:VEVENT
BEGIN:VEVENT
UID:1102c450-e0d7-11e1-9b23-0800200c9a66
RECURRENCE-ID:20120213T140000Z
DTSTART:20120213T140000Z
END:VEVENT
BEGIN:VEVENT
UID:1102c450-e0d7-11e1-9b23-0800200c9a66
RECURRENCE-ID:20120312T140000Z
DTSTART:20120312T140000Z
END:VEVENT
..etc..
END:VCALENDAR
In a recurring event, single instances can also be overridden. VObject also takes these into consideration. The reason we needed to specify a start and end-date, is because some recurrence rules can be 'never ending'.
You should make sure you pick a sane date-range. Because if you pick a 50 year time-range, for a daily recurring event; this would result in over 18K objects.
Note: Before sabre/vobject version 4, the
expand()method did not return a new calendar, but it edited the entire calendar in-place. So from version 4 to retrieve a calendar with only those events in the given period, you have to use the object returning fromexpand()(e.g.$vcalendar = $vcalendar->expand(new DateTime('2012-01-01'), new DateTime('2012-12-31'));).
sabre