Skip to content

RecurIterator#next never returns when the contracting BY* parts cannot all be satisfied #1038

Description

@mkmelin

Version

2.2.1

What happens

February never has a 30th, so this rule has no occurrences. Asking for the
second one never returns:

import ICAL from "ical.js";

const iter = ICAL.Recur.fromString("FREQ=DAILY;BYMONTH=2;BYMONTHDAY=30")
  .iterator(ICAL.Time.fromString("2026-01-01T00:00:00"));

iter.next(); // 2026-01-01T00:00:00
iter.next(); // never returns

FREQ=HOURLY;BYMONTH=2;BYMONTHDAY=30 hangs the same way. MONTHLY and
YEARLY do not, which is the tell.

Cause

The do ... while in next keeps stepping until check_contracting_rules
accepts the instance it has landed on. MONTHLY and YEARLY bail out of it
via invalid_count, but those counters only tick when the expansion itself
rejected the period, not when the contracting parts did, and the other
frequencies have no bail-out at all. So for a rule whose contracting parts
exclude everything the expansion produces, the loop runs for ever.

I will open a PR.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions