GetOccurrences includes the first event at the start/end even though it is not in RRule
I am implementing Telerik's KendoUI Scheduler control in a MVC web project. It has a calendar for users to enter scheduled tasks. Since it is open for the users to add/edit, any date can be selected to create a new event and the start/end times can be customized. This presents a scenario where the user creates an event on Friday but sets the recurrence rule to repeat only on Mondays.
In the HashSet<Occurrence> Calendar.GetOccurrences(..) method, it includes the start/end of the event even though it is not under the rrule.
I am using latest v2.2.32. See this following code for an example:
public static void StartEndEventShouldNotBeIncludedInOccurrences()
{
// Recur weekly every monday through the end of the day, April 5 2017
var rrule = new RecurrencePattern("FREQ=WEEKLY;UNTIL=20170405T115959;BYDAY=MO");
var vEvent = new Event
{
// the start/end datetimes for the event are on Friday March 10 2017
DtStart = new CalDateTime(DateTime.Parse("2017-03-10T14:00:00")),
DtEnd = new CalDateTime(DateTime.Parse("2017-03-10T18:00:00")),
RecurrenceRules = new List<IRecurrencePattern> { rrule },
};
var calendar = new Calendar();
calendar.Events.Add(vEvent);
// set the occurrences roll out to start at the event start time and go to the until time
var startSearch = new CalDateTime(DateTime.Parse("2017-03-10T14:00:00"));
var endSearch = new CalDateTime(DateTime.Parse("2017-04-05T11:59:59"));
var occurrences = calendar.GetOccurrences(startSearch, endSearch);
}
Below is screenshot of the occurrences. Why is the first occurrence at 3/10/2017 included in this list?

I do not think it should be. If I enter that recurrence pattern at: http://jakubroztocil.github.io/rrule/
it does not show the occurrence on Mar 10 but instead the first one on Mar 13.

Telerick's Scheduler calendar control does not show the event on March 10 nor does Telerik's client-side SchedulerEvent.expand(..) (http://docs.telerik.com/kendo-ui/api/javascript/data/schedulerevent#methods-expand).
So which is right?
I have a similar issue of the DtStart date not matching the RRULE and have figured out a work around using the RecurrencePatternEvaluator.
// 3/1/2017 is a wednesday so it shouldn't display in the occurrences
var vEvent = new Event {
DtStart = new CalDateTime(newDateTime(2017, 3, 1, 9, 0, 0)),
DtEnd = new CalDateTime(newDateTime(2017, 3, 1, 10, 0, 0))
};
var recurrenceRule = new RecurrencePattern(FrequencyDayType.Weekly, 1) {
ByDay = new IList<IWeekday> { new WeekDay(DayOfWeek.Thursday) }
};
var recurrenceEvaluator = new RecurrencePatternEvaluator(recurrenceRule);
var searchStart = new DateTime(2017, 3, 1, 0, 0, 0);
var searchEnd = new DateTime(2017, 3, 17, 0, 0, 0);
var correctOccurrences = recurrenceEvaluator.Evaluate(vEvent.DtStart, searchStart, searchEnd, false);
Occurrence should equal 3/2/2017, 3/9/2017, and 3/16/2017. By setting the parameter includeReferenceDateInResults to false only adds the DtStart to the occurrences if it matches the RRULE.
Thanks @streviranus for your work around. The RecurrencePatternEvaluator will be helpful though it presents another issue for my application since I am looking for the next occurrence's start and end times so that I can auto-adjust the entered times with the actual next occurrence. I think I will have to come up with a custom solution to either marry the the two HashSets or calculate the end time from the start time manually.
I think it would be best if that bool includeReferenceDateInResults flag could be a (optional) parameter in the GetOccurrences method.
@sonyisda1 same here I have to implement a custom solution and will use my correctOccurrences list to verify the first element matches the RRULE.
@rianjs can I +1 vote to add an optional bool includeReferenceDateInResults flag to the GetOccurrences method?
@rianjs can I +1 vote to add an optional bool includeReferenceDateInResults flag to the GetOccurrences method?
Sure. Alternatively, you could open a pull request to add it...
Sure. Alternatively, you could open a pull request to add it...
@rianjs when I have the time I can, it'll be a couple weeks at least tho.
I hear you: most of my current work on ical.net happens when I need changes (and bugfixes) because of work. :)
Encountered the same issue. It may cause devastating effect in Outlook because once you saved an event which actually fires zero times (while the current implementation of GetOccurrences returns 1 for it), Outlook lets you save such event successfully but future access to this event crashes Outlook. Outlook itself (when you create events in UI) does not allow start date to differ from the first date actually evaluated by the event rules. But you can do that with their object model, so it's very important to check if the event you're feeding to Outlook does have at least one actual occurrence.
Are there any plans to implement includeReferenceDateInResults parameter in GetOccurrences method in the near future?
Well, it seems I can just use RecurrencePatternEvaluator.Evaluate as I don't need actual occurrences, only their count.
I, however, noticed another issue. Looks like Until is exclusive, not inclusive. If event.Start is the same as recurPattern.Until and the event occurs the same weekday, I'm not getting the match. I understand it's artificial example (recurring weekly event which repeats only once and has the same start and end date and its weekday matches the same day) but it's still valid.
Event someEvent = new Event();
someEvent.Start = new CalDateTime(new DateTime(2018, 1, 25, 9, 0, 0));
someEvent.End = new CalDateTime(new DateTime(2018, 1, 25, 10, 0, 0));
var recurrenceRule = new RecurrencePattern(FrequencyType.Weekly, 1)
{
ByDay = new List<IWeekDay> { new WeekDay(DayOfWeek.Thursday) }
};
var recurrenceEvaluator = new RecurrencePatternEvaluator(recurrenceRule);
var searchStart = new DateTime(2018, 1, 25, 0, 0, 0);
var searchEnd = new DateTime(2018, 1, 25, 0, 0, 0);
var correctOccurrences = recurrenceEvaluator.Evaluate(someEvent.Start, searchStart, searchEnd, false);
https://github.com/rianjs/ical.net/issues/121 issue explains this is intended behavior, and I can understand that but there are scenarios when this should be different. So, maybe another parameter which controls that? DDay.iCal is indeed not the best source but Outlook behaves the same way. It delivers a single occurrence (not zero) for recurring event having the same start and end dates.
Currently, to make Until inclusive, I work this around by making searchEnd like this (so it covers the day in question completely but never spans to the next day, no matter which time is in searchEnd):
searchEnd.Date.Add(new TimeSpan(23, 59, 59))