builttoroam / device_calendar

A cross platform plugin for modifying calendars on the user's device
https://pub.dev/packages/device_calendar
BSD 3-Clause "New" or "Revised" License
270 stars 271 forks source link

RecurrenceRule needs different endDate #557

Closed erperejildo closed 3 months ago

erperejildo commented 3 months ago

I have something like this:

end: toDate,
recurrenceRule: device_calendar.RecurrenceRule(
        convertFrequency(frequency!),
),

The event is created ok, but despite I pass the endDate correctly, it creates events for a longer period.

This fixes it, but I was wondering why we'd need 2 end dates:

end: toDate,
recurrenceRule: device_calendar.RecurrenceRule(
        convertFrequency(frequency!),
       endDate: toDate,
),
IVLIVS-III commented 3 months ago

Please share a bit more of your code so we can fully understand your issue.

I believe the first endDate sets the end date of that single event instance. The second (nested) end date sets the last date on which to repeat multiple instances of your recurring event.

erperejildo commented 3 months ago

Please share a bit more of your code so we can fully understand your issue.

I believe the first endDate sets the end date of that single event instance. The second (nested) end date sets the last date on which to repeat multiple instances of your recurring event.

I don't have any problem with my code. It's working fine. I was trying to understand why is this necessary, because if I select in the calendar, let's say, from December 1st to December 31st, the end is the 31st but the endDate is also 31st. I won't have more events after December.

What is the scenario where those dates are different?

IVLIVS-III commented 3 months ago

As I tried to explain in my earlier comment, imagine the following scenario: You have an event that takes from 5pm-7pm for every day in December 2024.

You would create such an event as follows:

Event(
  calendarId,
  start: TZDateTime.local(2024, 12, 1, 17),  // 5pm on December 1st, 2024
  end: TZDateTime.local(2024, 12, 1, 19),  // 7pm on December 1st, 2024
  recurrenceRule: RecurrenceRule(
    RecurrenceFrequency.Daily,
    endDate: DateTime(2024, 12, 31),  // December 31st, 2024
  ),
)

As you can see in the example above, the • first instance of the repeating 2-hour event ends at 7pm on December 1st, 2024 (this is what end is for) • last instance of the repeating 2-hour event ends on December 31st, 2024 (this is what recurrenceRule.endDate is for)

If you set end and recurrenceRule.endDate to the same value, your event will only ever be repeated once, at which point you could just leave the whole recurrenceRule be null, which should have the same effect.

erperejildo commented 3 months ago

Ok, I see that now. The start/end is just related to the event itself.

In my case, users select the start and date from a calendar. They don't select any time because the event is always for the whole day. Does that mean that I need to pass always the same end and endDate? I don't see any problem after creating the events. For example, for a weekly event crated for December and sending same endDates, it creates the 5 events (1 per week).

I don't know if I could have any problem with other type of calendar of this should be sent differently with allDay: true.

Me event:

Event(
        calendar.id,
        title: title,
        start: Helpers.convertToTZDate(fromDate!),
        end: Helpers.convertToTZDate(toDate!),
        location: location,
        allDay: true,
        description: description,
        recurrenceRule: device_calendar.RecurrenceRule(
          Helpers.convertFrequency(frequency!),
          endDate: toDate,
        ),
      );
IVLIVS-III commented 3 months ago

You have two options, both are equally valid. It depends on your use case which one suits you better. Imagine your user selects December 1st, 2024 as start and December 5th, 2024 as end:

  1. Create 5 different event instances, each being 24 hours long, i.e. one full day each
  2. Create a single event instance spanning 5 days = 120 hours, i.e. five full days at once

Your code above shows a variation of option 2.


Details on option 1: 5 different events, each 24 hours:

Event(
  calendar.id,
  start: Helpers.convertToTZDate(fromDate!),  // December 1st, 2024
  end: Helpers.convertToTZDate(fromDate!),  // December 1st, 2024 as well
  allDay: true,  // event has same `start` and `end` date but is `allDay`, so 24 hours
  recurrenceRule: RecurrenceRule(
    RecurrenceFrequency.Daily,  // repeat each day until (and including):
    endDate: toDate,  // December 5th, 2024
  ),
)

If your user was to go in their calendar application and delete, say the event on December 3rd, 2024, there would still be the full day event on December 1st, 2nd, 4th, and 5th remaining, as they are different instances of an 24-hour event.


Details on option 2: a single event instance of 120 hours

Event(
  calendar.id,
  start: Helpers.convertToTZDate(fromDate!),  // December 1st, 2024
  end: Helpers.convertToTZDate(toDate!),  // December 5th, 2024
  allDay: true,  // event is `allDay` multi-day
  recurrenceRule: null,  // event never repeats, is only a single event spanning 5 days, you don't even need this line of code as `recurrenceRule` is `null` by default
)

If you chose option 2 and the user goes in their calendar application and tries to delete December 3rd, 2024, they would delete the single event, so the calendar would then be empty also on December 1st, 2nd, 4th, and 5th, i.e. either all or nothing.


Your code above is a variation of option two so far as you create a single event spanning (in my example) 5 full days = 120 hours. But you then specify to repeat the event until and including the date on which the first instance of your repeating event ends. This means in practice: stop repeating after the first time, i.e. don't repeat at all. At which point you could simply set recurrenceRule: null to achieve the same outcome.


I hope this clarifies what you are trying to understand. If there are any questions left, feel free to reply.

erperejildo commented 3 months ago

Ok, I think first option makes more sense in case the user wants to remove just one event. He'd have the option to remove the series anyway.

Since my default calendar was doing it right (that's why I couldn't see much difference), I forced it to use Google's calendar. First I saw what I was creating:

WhatsApp Image 2024-08-28 at 18 09 28_c6c0ab53

Definitely not right. The events should take one day.

So I made the change to send the same start/end date:

WhatsApp Image 2024-08-28 at 18 16 19_d9e2c6d6

That's more like it. Thanks!

Also, I noticed that I needed to have Google's calendar closed, otherwise, it wouldn't display the new events. I had to close it and open it again, but sometimes twice. Do you know why?

IVLIVS-III commented 3 months ago

I could only guess as to why the events are delayed. I think it just takes some time for your Google Calendar to sync with the system calendar.

Maybe this discussion is helpful: #534