diff --git a/lib/ical/recur_expansion.js b/lib/ical/recur_expansion.js index 2694b3a1..1da38e94 100644 --- a/lib/ical/recur_expansion.js +++ b/lib/ical/recur_expansion.js @@ -198,6 +198,21 @@ class RecurExpansion { } } + /** + * Compare two ICAL.Time objects. When the second parameter is a timeless date + * and the first parameter is date-with-time, strip the time and compare only + * the days. + * + * @private + * @param {ICAL.Time} a The one object to compare + * @param {ICAL.Time} b The other object to compare + */ + _compare_special(a, b) { + if (!a.isDate && b.isDate) + return new Time({ year: a.year, month: a.month, day: a.day }).compare(b); + return a.compare(b); + } + /** * Retrieve the next occurrence in the series. * @return {ICAL.Time} @@ -248,9 +263,10 @@ class RecurExpansion { // check the negative rules if (this.exDate) { - compare = this.exDate.compare(this.last); + //EXDATE can be in DATE format, but DTSTART is in DATE-TIME format + compare = this._compare_special(this.last, this.exDate); - if (compare < 0) { + if (compare > 0) { this._nextExDay(); } @@ -397,10 +413,12 @@ class RecurExpansion { if (component.hasProperty('exdate')) { this.exDates = this._extractDates(component, 'exdate'); // if we have a .last day we increment the index to beyond it. + // When DTSTART is in DATE-TIME format, EXDATE is in DATE format and EXDATE is + // the date of DTSTART, _compare_special finds this out and compareTime fails. this.exDateInc = binsearchInsert( this.exDates, this.last, - (a, b) => a.compare(b) + this._compare_special ); this.exDate = this.exDates[this.exDateInc]; diff --git a/samples/rdate_exdate.ics b/samples/rdate_exdate.ics new file mode 100644 index 00000000..4ff511f6 --- /dev/null +++ b/samples/rdate_exdate.ics @@ -0,0 +1,8 @@ +BEGIN:VCALENDAR +BEGIN:VEVENT +UID:123 +DTSTART:20240609T030000Z +RRULE:FREQ=DAILY;INTERVAL=1;COUNT=4 +EXDATE;VALUE=DATE:20240611 +END:VEVENT +END:VCALENDAR diff --git a/test/recur_expansion_test.js b/test/recur_expansion_test.js index eb5d37d1..3cdfc7b9 100644 --- a/test/recur_expansion_test.js +++ b/test/recur_expansion_test.js @@ -329,4 +329,17 @@ suite('recur_expansion', function() { }); + suite('EXDATE and DTSTART have different value type', function() { + createSubject('rdate_exdate.ics'); + test('Compare EXDATE;VALUE=DATE and DTSTART;VALUE=DATE-TIME', function() { + let dates = [], next; + while ((next = subject.next())) + dates.push(next.toJSDate()); + assert.deepEqual(dates, [ + new Date('2024-06-09T03:00:00.000Z'), + new Date('2024-06-10T03:00:00.000Z'), + new Date('2024-06-12T03:00:00.000Z') + ]); + }); + }); });