ical.net
ical.net copied to clipboard
Concrete RecurrencePattern for all day event is not parsed correctly (with code example)
Overview
I have a code example here.
Application creates CalendarEvent
with IsAllDay
flag, Start
and End
date.
And then adds RecurrenceRules
as following: "RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=MO;BYSETPOS=1"
(RRULE).
Expects that this RRULE should create an event that happens each Monday. But it happens each day.
So when I use CalendarEvent.GetOccurrences
it gives me always this event event for days when it should not happen.
Code Examples
In application I start from Start day and tries to use CalendarEvent.GetOccurrences
on each next day. Provide some code below or on GitHub here.
Demo.cs
public class Demo
{
private const string LocalTimeZone = "Europe/Minsk";
private readonly CalendarEvent calendarEvent;
public Demo()
{
// start day is Wednesday
var startDate = DateTimeOffset.Parse("2020-08-05T21:00:00.0000000+00:00");
var localStartDate = ToCal(startDate).ToTimeZone(LocalTimeZone);
var endDate = DateTimeOffset.Parse("2020-11-06T20:59:59.0000000+00:00");
var localEndDate = ToCal(endDate).ToTimeZone(LocalTimeZone);
calendarEvent = new CalendarEvent
{
Status = "Holiday",
Start = localStartDate,
End = localEndDate,
IsAllDay = true,
};
// RRULE for Monthly each Monday
calendarEvent.RecurrenceRules.Add(
new RecurrencePattern("RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=MO;BYSETPOS=1"));
}
public string GetStatus(DateTimeOffset now)
{
var localNow = ToCal(now).ToTimeZone(LocalTimeZone);
var found = calendarEvent.GetOccurrences(localNow, localNow);
return ExtractStatus(found.FirstOrDefault());
}
private IDateTime ToCal(DateTimeOffset o) =>
new CalDateTime(o.UtcDateTime);
private string ExtractStatus(Occurrence x) =>
((CalendarEvent) x?.Source)?.Status;
}
Program.cs
var now = DateTimeOffset.Parse("2020-08-07T11:31:38.1222194+00:00");
var demo = new Demo();
var count = 0;
var maxCount = 100;
while (count < maxCount)
{
System.Console.WriteLine($"{now.Date.ToShortDateString()} - {demo.GetStatus(now)}");
now = now.AddDays(1);
count++;
}
System.Console.WriteLine("Press [Enter] to exit.");
System.Console.ReadLine();
How i tested RRULE online (not sure if it is correct approach)
I tried to find online parsers for RRULE (because it might be that my rule is wrong). And found this one http://worthfreeman.com/projects/online-icalendar-recurrence-event-parser/ And if I specify the following
DTSTART:20200805T000000
DTEND:20201106T115900
RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=MO;BYSETPOS=1
It specifies correct days when event happens. Only Mondays.
Many thanks for any help or comments.
@anichiporovich-luware I am not sure if I got you right.
Between 2020-08-05 (Wednesday) and 2020-11-06 (Friday) you want every Monday an all-day event called "Holiday". Is this right?
You have defined an event, that lasts for 3 month (2020-08-05 to 2020-11-06) and will get repeated every Monday forever since the RRule
is not terminated.
You could define your event like this:
/// monday
var startDate = Datetime.Parse("2020-08-10");
calendarEvent = new CalendarEvent {
Status = "Holiday",
Start = startDate,
IsAllDay = true,
};
// RRULE for Monthly each Monday
calendarEvent.RecurrenceRules.Add(
new RecurrencePattern("RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=MO;BYSETPOS=1;UNTIL=2020-11-06"));
Consider following points:
-
calendarEvent
already represents the first occurrence. That's whystartDate
is set to"2020-08-10"
instead of"2020-08-05"
- Termination of the recurrence is defined inside
RRULE
byUNTIL=2020-11-06
@rootGst thanks a lot for your response.
I see that the example that I sent has incorrect usage of RRULE
and understanding of what startDate
should be set to.
So I changed it to the following
var startDate = DateTimeOffset.Parse("2020-08-10");
var localStartDate = ToCal(startDate).ToTimeZone(LocalTimeZone);
calendarEvent = new CalendarEvent
{
Status = "Holiday",
Start = localStartDate,
IsAllDay = true,
};
calendarEvent.RecurrenceRules.Add(
new RecurrencePattern("RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=MO;BYSETPOS=1;UNTIL=2020-11-06"));
But my original question was a bit messed up. It contained two questions, about event that exists after End Date and it was solved with UNTIL
that your suggested to use. And another part is that I would expect to have event on Monday 2020-08-10 (2020 August 10), and then next Monday 2020-08-17. And I did not manage to achieve it in this code sample (see below)
To test it in Demo.cs
there is method GetStatus(DateTime
that simply return event name
If I have an issue here e.g. incorrect usage of iCal.Net API, please let me know.
Example below (or you can take a look at my code on GitHube here.
public string GetStatus(DateTimeOffset now)
{
var localNow = ToCal(now).ToTimeZone(LocalTimeZone);
var found = calendarEvent.GetOccurrences(localNow, localNow);
return ExtractStatus(found.FirstOrDefault());
}
private IDateTime ToCal(DateTimeOffset o) =>
new CalDateTime(o.UtcDateTime);
private string ExtractStatus(Occurrence x) =>
((CalendarEvent) x?.Source)?.Status;
At the end in Program.cs
I have a code that executes GetStatus
each day starting from 2020-08-09. So what I would expect to get is the name of event like 'Holiday' for only two dates, but after I applied changes e.g. the same code that you suggested above, I do not have events
output looks like this
8/10/2020 - <None>
8/11/2020 - <None>
8/12/2020 - <None>
8/13/2020 - <None>
8/14/2020 - <None>
8/15/2020 - <None>
8/16/2020 - <None>
8/17/2020 - <None>
8/18/2020 - <None>
8/19/2020 - <None>
8/20/2020 - <None>
8/21/2020 - <None>
8/22/2020 - <None>
8/23/2020 - <None>
NOTE That when I do almost the same with slight difference - specify end date
var startDate = DateTimeOffset.Parse("2020-08-10");
var localStartDate = ToCal(startDate).ToTimeZone(LocalTimeZone);
var endDate = DateTimeOffset.Parse("2020-11-06");
var localEndDate = ToCal(endDate).ToTimeZone(LocalTimeZone);
calendarEvent = new CalendarEvent
{
Status = "Holiday",
Start = localStartDate,
End = localEndDate,
IsAllDay = true,
};
calendarEvent.RecurrenceRules.Add(
new RecurrencePattern("RRULE:FREQ=MONTHLY;INTERVAL=1;BYDAY=MO;BYSETPOS=1;UNTIL=2020-11-06"));
Then the output is the following
8/9/2020 - <None>
8/10/2020 - Holiday
8/11/2020 - Holiday
8/12/2020 - Holiday
8/13/2020 - Holiday
8/14/2020 - Holiday
8/15/2020 - Holiday
8/16/2020 - Holiday
8/17/2020 - Holiday
8/18/2020 - Holiday
8/19/2020 - Holiday
8/20/2020 - Holiday
8/21/2020 - Holiday
8/22/2020 - Holiday
8/23/2020 - Holiday
But what I want is to have "Holiday" only for 2020-08-10 and 2020-08-17. Could you please help me to understand how can I achieve it.
Thanks a lot for your help in advance.
Best regards, Alex.