Skip to content

Commit

Permalink
recur_expansion: EXDATE can be DATE and DTSTART can be DATE-TIME
Browse files Browse the repository at this point in the history
When EXDATE is in DATE format and DTSTART is DATE-TIME, then
to determine whether an occurrence shall be excluded, the
occurrence shall be converted to DATE and then compared to EXDATE.

This applies also for the very first EXDATE, when it coincides with
DTSTART.
  • Loading branch information
dilyanpalauzov committed Jun 9, 2024
1 parent 38eeea5 commit ac0ad56
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 3 deletions.
24 changes: 21 additions & 3 deletions lib/ical/recur_expansion.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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];
Expand Down
8 changes: 8 additions & 0 deletions samples/rdate_exdate.ics
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions test/recur_expansion_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
]);
});
});
});

0 comments on commit ac0ad56

Please sign in to comment.