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:
UNTIL
for an end date,INTERVAL
for for example "every 2 days",COUNT
to stop recurring after x items,FREQ=DAILY
to recur every day, andBYDAY
to limit it to certain days,FREQ=WEEKLY
to recur every week,BYDAY
to expand this to multiple weekdays in every week andWKST
to specify on which day the week starts,FREQ=MONTHLY
to recur every month,BYMONTHDAY
to expand this to certain days in a month,BYDAY
to expand it to certain weekdays occurring in a month, andBYSETPOS
to limit the last two expansions,FREQ=YEARLY
to recur every year,BYMONTH
to expand that to certain months in a year, andBYDAY
andBYWEEKDAY
to expand theBYMONTH
rule 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'));
).