mangstadt / biweekly

biweekly is an iCalendar library written in Java.
BSD 2-Clause "Simplified" License
323 stars 44 forks source link

start date (dtstart) is ignored as first date when iterating recurrence rules (rrule) that does not match this date #88

Closed gaspardpetit closed 5 years ago

gaspardpetit commented 5 years ago

When iterating a RRULE recurrence, I would expect the start date to be the first date returned, even if it does not match the RRULE. It is not the case:

@Test
public void givenRRULENotMatchingStartDate_whenIterateFirst_ensureIsStartDate()
{
    // given
    final String rrule = "FREQ=WEEKLY;BYDAY=MO"; // weekly, every Monday
    final Instant dtstart = Instant.parse("2019-08-02T00:00:00Z"); // starting on a Friday

    // when
    RecurrenceRuleScribe scribe = new RecurrenceRuleScribe();
    ParseContext context = new ParseContext();
    context.setVersion(ICalVersion.V2_0);
    RecurrenceRule recurrenceRule = scribe.parseText(rrule, null, new ICalParameters(), context);
    DateIterator iter = recurrenceRule.getDateIterator(Date.from(dtstart), TimeZone.getTimeZone("UTC"));
    Date next = iter.next();

    // ensure
    Assertions.assertEquals(Instant.parse("2019-08-02T00:00:00Z"), next.toInstant());
}

Results in:

Expected :2019-08-02T00:00:00Z
Actual   :2019-08-05T00:00:00Z

This may be ruled out as something specific for this library, but it comes as a surprise since it diverges from the RFC standard (5545 / 2445) which states under 3.8.2.4. Date-Time Start:

Description: Within the "VEVENT" calendar component, this property defines the start date and time for the event.

 Within the "VFREEBUSY" calendar component, this property defines
 the start date and time for the free or busy time information.
 The time MUST be specified in UTC time.

 Within the "STANDARD" and "DAYLIGHT" sub-components, this property
 defines the effective start date and time for a time zone
 specification.  This property is REQUIRED within each "STANDARD"
 and "DAYLIGHT" sub-components included in "VTIMEZONE" calendar
 components and MUST be specified as a date with local time without
 the "TZID" property parameter.

Additionally, the getDateIterator documents the following:

  • @param startDate the date that the recurrence starts (typically, the
  • value of the accompanying {@link DateStart} property)

This suggests that this is the start of the recurrence, even though this date is not returned as the first element of the iteration when it does not match the provided RRULE

Finally, the method refers to:

Suggesting compliance, which is not the case. I would suggest either fixing for compliance or documenting the difference.

Cheers,

Gaspard

gaspardpetit commented 5 years ago

I take this one back, apparently this is how Outlook/google/apple calendars and ical4j handle dtstart as well.... :)

mangstadt commented 5 years ago

Hehe no problem. :)