Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Daylight savings occurrences bug #304

Open
gf3 opened this issue Feb 14, 2024 · 2 comments
Open

Daylight savings occurrences bug #304

gf3 opened this issue Feb 14, 2024 · 2 comments

Comments

@gf3
Copy link

gf3 commented Feb 14, 2024

hi all, first of all—thank you for a wonderful library!

i've encountered what seems to be a daylight savings issue in 0.10.3 when trying to generate occurences across the daylight savings boundary. when attempting to pull DateTimes after the boundary the stream seems to enter some sort of infinite loop and does not return. here's a reproduction:

{:ok, schedule} = Cocktail.Schedule.from_i_calendar("DTSTART;TZID=America/Toronto:20230101T000000\nRRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR")
timezone = "America/Toronto"
start = ~D[2024-03-01] |> DateTime.new!(~T[00:00:00], timezone)
stop = ~D[2024-03-15] |> DateTime.new!(~T[00:00:00], timezone)
stream = schedule |> Cocktail.Schedule.end_all_recurrence_rules(stop) |> Cocktail.Schedule.occurrences(start)

note: daylight savings begins on March 10, 2024. so if we take take the first four occurrences they should fall just before the boundary:

iex> stream |> Enum.take(4)
[#DateTime<2024-03-01 00:00:00-05:00 EST America/Toronto>,
#DateTime<2024-03-04 00:00:00-05:00 EST America/Toronto>,
#DateTime<2024-03-06 00:00:00-05:00 EST America/Toronto>,
#DateTime<2024-03-08 00:00:00-05:00 EST America/Toronto>]

now, the next occurrence should fall on March 11, 2024, if we attempt to take the first five occurrences the code will hang indefinitely:

iex> stream |> Enum.take(5)

BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
(l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
^C
@gf3
Copy link
Author

gf3 commented Feb 14, 2024

i believe Cocktail.Validation.Day.next_time/3 is improperly returning change status:

validation = %Cocktail.Validation.Day{days: [1, 3, 5]}
timezone = "America/Toronto"
start_time = DateTime.new!(~D[2023-01-01], ~T[00:00:00], timezone)

time1 = DateTime.new!(~D[2024-03-06], ~T[00:00:00], timezone)
time2 = DateTime.new!(~D[2024-03-10], ~T[00:00:00], timezone)
iex> Cocktail.Validation.Day.next_time(validation, time1, start_time)
{:no_change, #DateTime<2024-03-06 00:00:00-05:00 EST America/Toronto>}
iex> Cocktail.Validation.Day.next_time(validation, time2, start_time)
{:change, #DateTime<2024-03-10 00:00:00-05:00 EST America/Toronto>}

@gf3
Copy link
Author

gf3 commented Feb 14, 2024

i was able to find the culprit, it's Cocktail.Util.shift_time/2:

iex> time = DateTime.new!(~D[2024-03-10], ~T[00:00:00], timezone)
#DateTime<2024-03-10 00:00:00-05:00 EST America/Toronto>

iex> Cocktail.Util.shift_time(time, days: 1)
#DateTime<2024-03-10 23:00:00-04:00 EDT America/Toronto>

iex> Timex.shift(time, days: 1)
#DateTime<2024-03-11 00:00:00-04:00 EDT America/Toronto>

this is what causes the :change/:no_change infinite loop in Cocktail.RuleSet.do_next_time/3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant