When working with calendar items created with recurrence patterns, there’s no immediately obvious way through the object model to expose the individual recurrence items. If you create a calendar event with a daily recurrence pattern which generates 6 separate events, you’re only ever given one item when looking for it through code.
Using CAML, it’s easy to get all 6 items back as individual items through the use of the DateRangesOverlap element.
The structure of the DateRangesOverlap element looks like:
<DateRangesOverlap> <FieldRef Name='EventDate' /> <FieldRef Name='EndDate' /> <FieldRef Name='RecurrenceID' /> <Value IncludeTimeValue=\"TRUE\" Type='DateTime'> <Now /> </Value> </DateRangesOverlap>
What this does is bring back any recurring item where the start date (EventDate) and the end date (EndDate) overlap the value specified, which in the above example is Now
Possible values here are:
- Year – Retrieves everything from a year in the past\future using today’s date
- Now – Brings back everything up to two years from today’s date and time
- Month – Brings back all items for the current month
- Day – As it sounds, everything that occurs within the current day
Using the SPQuery class you can set the date the above acts upon, so instead of the current date and time it could be a past or future date.
Take a look at the following example:
SPQuery query = new SPQuery(); query.Query = "<Where><DateRangesOverlap><FieldRef Name='EventDate' /><FieldRef Name='EndDate' /><FieldRef Name='RecurrenceID' /><Value Type='DateTime'><Month /></Value></DateRangesOverlap></Where>"; query.ExpandRecurrence = true; query.CalendarDate = DateTime.Now.AddMonths(-2);
The important thing to remember when using the DateRangesOverlap element is to also set the ExpandRecurrence property of your SPQuery class to true, otherwise you won’t get any recurring items back when running it.
The example above will query for recurring events and return all that occurred during the month two months prior to the current date.
You’ll also get back any non-recurring item that exists within the specified time period, which includes single all day events and one off calendar entries.
So, based on a CalendarDate of 1 May 2013, specifying Year would bring back items that occurred between 1 May 2012 and up to 1 May 2014.
For Now, you would get back items between 1 May 2013 and 1 May 2015.
Day and Month should be fairly self explanatory.
Adding the IncludeTimeValue attribute to the value node will further filter your results based on the time specified for the CalendarDate property, or the current time if this is not set.