ical-org / ical.net

ical.net - iCalendar library for .Net
Other
797 stars 231 forks source link

Incorrect start date for occurrence? #544

Closed LoyalPotato closed 1 month ago

LoyalPotato commented 2 years ago

I ran this code in a dotnetfiddle

using System;
using System.Linq;
using System.Collections.Generic;
using Ical.Net;
using Ical.Net.DataTypes;
using Ical.Net.CalendarComponents;

public class Program
{
    public static void Main()
    {
        var now = DateTime.Parse("2021-09-16T10:00:00");
        var later = now.AddMonths(1);

        //Repeat daily for 5 days
        var rrule = new RecurrencePattern(FrequencyType.Daily, 1);

        var e = new CalendarEvent
        {
            Start = new CalDateTime(now),
            End = new CalDateTime(later),
            RecurrenceRules = new List<RecurrencePattern> { rrule },
        };

        var calendar = new Calendar();
        calendar.Events.Add(e);

        var startSearch = new CalDateTime(DateTime.Parse("2021-10-16T00:00:00"));
        var endSearch = new CalDateTime(DateTime.Parse("2021-10-21T23:59:59"));
        var startTimes = calendar.GetOccurrences(startSearch, endSearch).Select(x => x.Period.StartTime.AsDateTimeOffset);
        startTimes.Dump();
    }
}

And the result was

Dumping object(System.Linq.SelectEnumerableIterator`2[Ical.Net.DataTypes.Occurrence,DateTimeOffset])
[
   09/16/2021 10:00:00 +00:00
   ,
   10/15/2021 10:00:00 +00:00
   ,
   10/16/2021 10:00:00 +00:00
   ,
   10/17/2021 10:00:00 +00:00
   ,
   10/18/2021 10:00:00 +00:00
   ,
   10/19/2021 10:00:00 +00:00
   ,
   10/20/2021 10:00:00 +00:00
   ,
   10/21/2021 10:00:00 +00:00
]

Based on the defined start search date of "2021-10-16" why is the first two dates (09/16/2021 10:00:00 +00:00, 10/15/2021 10:00:00 +00:00) shown in the dump. Upon further testing, changing the initial hour to the same one as the now:

var startSearch = new CalDateTime(DateTime.Parse("2021-10-16T10:00:00"));

omits the first entry of 09/16/2021 10:00:00 +00:00. Changing it to:

var startSearch = new CalDateTime(DateTime.Parse("2021-10-16T11:00:00"));

Stops showing the second value of 10/15/2021 10:00:00 +00:00.

GCymbala commented 2 years ago

I'd like to second this issue. GetOccurrences seems pretty broken at the moment. I'm currently using 4.1.11. Previously, I'd been trying to parse the recurrence rules myself and create new events based on those rules, so I understand that it's particularly tricky with all the various permutations. I've got an event like this:

BEGIN:VEVENT
DESCRIPTION:Description
RRULE:FREQ=WEEKLY;UNTIL=20230420T153000Z;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;WK
 ST=SU
EXDATE;TZID=Mountain Standard Time:20220929T093000
UID:040000008200E00074C5B7101DF2E00800000000C0C930288A9AD801000000000000000
 0100000001A1C8658F6EA5546C3DEFA6FAA3DCC57
SUMMARY:XYZ Standup
DTSTART;TZID=Mountain Standard Time:20220920T093000
DTEND;TZID=Mountain Standard Time:20220920T100000
CLASS:PUBLIC
PRIORITY:5
DTSTAMP:20221020T201537Z
TRANSP:OPAQUE
STATUS:CONFIRMED
SEQUENCE:3
LOCATION:Somewhere
END:VEVENT

But when I call it with GetOccurrences(searchStart, searchEnd); where searchStart is a CalDateTime with a value of {10/20/2022 2:15:37 PM} and searchEnd is a CalDateTime with a value of {11/17/2022 2:15:37 PM}, I get the following:

9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
9/20/2022 9:30:00 AM    9/20/2022 10:00:00 AM   XYZ Standup
Wazmin commented 1 year ago

Hello there ;)

In fact your issues come from your Event definition. to create a recurrent event you have to define the first instance of this event and then writre the recurrence rule that will duplicate it.

So for LoyalPotato, you defined an event that occurs during one month var later = now.AddMonths(1); and then via rrule you make it repetable daily.

If you want an event that occurs every day during one month, you should define the first event with a startTime, and optionaly and endTime, and then add Daily recurrence rule with an UNTIL date or provide the number of event occurence you want to have via COUNT property.

For GCymbala issue,

I did that in c#

var firstStart = new CalDateTime(new DateTime(2022, 9, 10, 9, 30, 0));
var firstEnd = new CalDateTime(new DateTime(2022, 9, 10, 10, 0, 0));
var vEvent = new CalendarEvent { DtStart = firstStart, DtEnd = firstEnd};

var rRule = new RecurrencePattern("RRULE:FREQ=WEEKLY;UNTIL=20230420T153000Z;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR;WKST=SU");
vEvent.RecurrenceRules.Add(rRule);

var calendar = new Calendar();
calendar.Events.Add(vEvent);

var searchStart = new DateTime(2022, 10, 20, 2, 15, 37);
var searchEnd = new DateTime(2022, 11, 17, 2, 15, 37);
var occurrences = calendar.GetOccurrences(searchStart, searchEnd).OrderBy(o => o.Period.StartTime).ToList();

That retrieve 20 occurences that seems to follow the rules, I don't have the same behaviour :/

YmlySilavong commented 1 year ago

Hello there,

I have also encountered an issue with GetOccurrences with weekly recurring occurrence:

based on this example to list occurences between two dates https://dotnetfiddle.net/eoMrsO

I have changed the original code to this:

const string ics =
@" BEGIN:VCALENDAR
BEGIN:VEVENT
DTSTART:20230504
RRULE:FREQ=WEEKLY;BYDAY=SA,SU
END:VEVENT
END:VCALENDAR
";    
var calendar = Calendar.Load(ics);
var list = calendar.GetOccurrences(DateTime.Parse("2023-05-01"), DateTime.Parse("2023-05-18"));

foreach (var item in list)
{     
  Console.WriteLine(item.ToString());
}

When this code is executed, it shows: CalendarEvent (05/04/2023) CalendarEvent (05/06/2023) CalendarEvent (05/07/2023) CalendarEvent (05/13/2023) CalendarEvent (05/14/2023)

If I understand iCal correctly, the first entry (05/04/2023) should have been displayed since it is a Thrusday and I have chosen a repeat rule only on saturdays and sundays.

Last 4 entries are correct.

If we change the value of "DTSTART", let say on the 3rd of May, the first occurrence will be the 3rd instead of the 4th.