Start date returns in some cases when using google

2019-03-26 16:25发布

问题:

I ran through a lot of RRULEs just for testing out the performance of google-rfc-2445 (a Java implementation of IETF RFC 2445 iCalendar).

I saw that I got the start date back in some cases in the returning list from the method.

The test is very simple:

private static void runGoogleTests() throws ParseException
{
    DateTimeZone dtz = DateTimeZone.UTC;
    DateTime dtStart = new DateTime("2014-11-22T00:00:00Z", dtz);//SATURDAY
    DateTimeIterable dti = DateTimeIteratorFactory.createDateTimeIterable("RRULE:FREQ=WEEKLY;COUNT=10;BYDAY=MO", dtStart, dtz, true);

    System.out.println("Size of iterable = " + Iterators.size(dti.iterator()));
    for(DateTime dateTime : dti)
    {
        System.out.println(dateTime);
    }
}

The list returned by the factory returns this list.

The first date is the start date and it's a saturday that should not be there. The RRULE also contained a COUNT=10 so why return 11?

Size of iterable = 11
2014-11-22T00:00:00.000Z
2014-11-24T00:00:00.000Z
2014-12-01T00:00:00.000Z
2014-12-08T00:00:00.000Z
2014-12-15T00:00:00.000Z
2014-12-22T00:00:00.000Z
2014-12-29T00:00:00.000Z
2015-01-05T00:00:00.000Z
2015-01-12T00:00:00.000Z
2015-01-19T00:00:00.000Z
2015-01-26T00:00:00.000Z

Someone using the Google-rfc-2445 must have encountered this problem before?

I posted the issue on the projects page but it's very quiet there. Link to the issue on google-rfc-2445 page

回答1:

RFC2445 section 4.3.10 Recurrence Rule specifies that

[...] The COUNT rule part defines the number of occurrences at which to range-bound the recurrence. The "DTSTART" property value, if specified, counts as the first occurrence. [...]

so while the presence of the DTSTART in the returned list is normal, what is less expected is the size of the returned list.

Given the RFC2445 specification, it makes more sense to have the DTSTART being the first instance of the recurrence to also insure that other calendars understand the ical file properly.

Also to be noted RFC2445 is obsoleted by RFC5545 which also specifies the DTSTART as the first instance of the RRULE (and even emphasizes it, note: the added word always (empahsis added by me)

RFC5545 RRULE section: The COUNT rule part defines the number of occurrences at which to range-bound the recurrence. The "DTSTART" property value always counts as the first occurrence.



回答2:

Try something like this:

public static DateTimeIterator createDateTimeIterator(
        final String repeatRules,
        final DateTime scheduleStart,
        final DateTimeZone timeZone) throws ParseException {

    DateTime start = scheduleStart;
    String exdate = "";
    final RRule rrule = new RRule(repeatRules);
    if (rrule.getFreq().ordinal() > Frequency.DAILY.ordinal()) {
        start = start.minusDays(1);
        exdate = "\nEXDATE:"
                + ISODateTimeFormat.basicDateTimeNoMillis().print(start.withZone(timeZone).toLocalDateTime());
    }

    final DateTimeIterable dateIterable = DateTimeIteratorFactory.createDateTimeIterable(
            repeatRules + exdate,
            start,
            timeZone,
            true);

    return dateIterable.iterator();

}

The idea is to start the sequence one day earlier and to exclude the first date by using EXDATE rule.