ical.net
ical.net copied to clipboard
Can't get proper occurences with Until set to UTC
TLDR: When Start/End time is in a timezone and Until is set in UTC, it is not converted correctly and the last occurence is missed.
Example: Start date is 15th Nov from 14:00 to 15:00 Sofia local time (UTC + 2). Until is set to 22nd Nov at 12:00 (UTC). GetOccurrences returns 7 results instead of 8th. The occurrence at 22nd Nov is not included.
Repro:
`
var hourStartUtc = 12;
var startDate = new CalDateTime(new DateTime(2018, 11, 15).AddHours(hourStartUtc + 2), "Europe/Sofia");
var vevent = new CalendarEvent
{
Start = startDate,
End = startDate.AddHours(1)
};
var rrule = new RecurrencePattern
{
Interval = 1,
Until = new DateTime(2018, 11, 22, hourStartUtc, 0, 0, DateTimeKind.Utc),
Frequency = FrequencyType.Daily
};
vevent.RecurrenceRules.Add(rrule);
var occurrences = vevent.GetOccurrences(new DateTime(2018, 11, 1), DateTime.MaxValue);
I found within the codebase that the method ProcessRecurrencePattern(IDateTime referenceDate) attempts to convert the UNTIL value to the timezone of DtStart, but it seems to me that it just creates a CalDateTime from the current UTC value without adjusting the timezone:
`
if (r.Until != DateTime.MinValue)
{
r.Until = DateUtil.MatchTimeZone(referenceDate, new CalDateTime(r.Until, referenceDate.TzId)).Value;
}
Shouldn't it be new CalDateTime(r.Until, "UTC").ToTimeZone(referenceDate.TzId) provided referenceDate.TzId is not null? This fixes it for me and applies the expected behavior.
Duplicate of or at least related to #406?
@ivan-prodanov I'm not sure if it's good to convert the UNTIL value to UTC in all cases. According to RFC 5545 Page 41 the definition of UNTIL is
"... Furthermore, if the "DTSTART" property is specified as a date with local time, then the UNTIL rule part MUST also be specified as a date with local time. If the "DTSTART" property is specified as a date with UTC time or a date with local time and time zone reference, then the UNTIL rule part MUST be specified as a date with UTC time." The local time form is simply a time value that does not contain the UTC designator nor does it reference a time zone (e.g. 11:00 PM) . If you're never receiving events with that date time format I'm sure your're fine with your solution.
I'm having troubles with an UNTIL value in an reccurrence rule too and I fixed it that way:
r.Until = DateUtil.MatchTimeZone(referenceDate, new CalDateTime(r.Until, r.Parameters.Get("TZID"))).Value;
I'm fetching the time zone from the recurrence pattern parameters which contains "UTC" if the UNTIL date is in UTC format and which is null if the UNTIL date is a local time. The new CalDateTime is then either created as UTC or local date and converted to the referenceDate time zone correctly.
Hello, i have the same issue for positive UTC (UTC + 1 in my case)
correcting this :
if (r.Until != DateTime.MinValue) { r.Until = DateUtil.MatchTimeZone(referenceDate, new CalDateTime(r.Until, referenceDate.TzId)).Value; }
to this :
if (r.Until != DateTime.MinValue) { r.Until = DateUtil.MatchTimeZone(referenceDate, new CalDateTime(r.Until, "UTC")).Value; }
Seems to resolve the problem, and have no impact on tests with negativ UTC.
@rianjs do you like solution suggested @McGery ? if we create a PR would you accept it ?
The issue is not solved yet. To get the last occurrence into the occurrences HashSet
I converted calendar event's Start and End values to UTC.
calendarEvent.Start.Value = calendarEvent.Start.AsUtc;
calendarEvent.End.Value = calendarEvent.End.AsUtc;
then GetOccurences
has worked as expected.
Calendar calendar = new();
calendar.Events.Add(calendarEvent);
var occurrences = calendar.GetOccurrences(start, end);