Skip to content

Commit

Permalink
Fix recurrence iteration where there is a negative BYMONTHDAY rule. (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
darktrojan authored Sep 8, 2022
1 parent 5df3565 commit 7fb7b51
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 21 deletions.
16 changes: 9 additions & 7 deletions lib/ical/recur_iterator.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ ICAL.RecurIterator = (function() {
this.last.second = this.setup_defaults("BYSECOND", "SECONDLY", this.dtstart.second);
this.last.minute = this.setup_defaults("BYMINUTE", "MINUTELY", this.dtstart.minute);
this.last.hour = this.setup_defaults("BYHOUR", "HOURLY", this.dtstart.hour);
this.last.day = this.setup_defaults("BYMONTHDAY", "DAILY", this.dtstart.day);
var dayOffset = this.last.day = this.setup_defaults("BYMONTHDAY", "DAILY", this.dtstart.day);
this.last.month = this.setup_defaults("BYMONTH", "MONTHLY", this.dtstart.month);

if (this.rule.freq == "WEEKLY") {
Expand Down Expand Up @@ -301,13 +301,15 @@ ICAL.RecurIterator = (function() {
throw new Error("Malformed values in BYDAY part");
}

} else if (this.has_by_data("BYMONTHDAY")) {
if (this.last.day < 0) {
var daysInMonth = ICAL.Time.daysInMonth(this.last.month, this.last.year);
this.last.day = daysInMonth + this.last.day + 1;
}
}
} else if (this.has_by_data("BYMONTHDAY") && dayOffset < 0) {
// Attempting to access `this.last.day` will cause the date to be normalised and
// not return a negative value. We keep the value in a separate variable instead.

// Now change the day value so that normalisation won't change the month.
this.last.day = 1;
var daysInMonth = ICAL.Time.daysInMonth(this.last.month, this.last.year);
this.last.day = daysInMonth + dayOffset + 1;
}
},

/**
Expand Down
55 changes: 41 additions & 14 deletions test/recur_iterator_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -516,12 +516,12 @@ suite('recur_iterator', function() {

// monthly, the third instance of tu,we,th
testRRULE('FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3', {
byCount: true,
dates: [
'1997-09-04T09:00:00',
'1997-10-07T09:00:00',
'1997-11-06T09:00:00'
]
byCount: true,
dates: [
'1997-09-04T09:00:00',
'1997-10-07T09:00:00',
'1997-11-06T09:00:00'
]
});

//monthly, each month last day that is monday
Expand Down Expand Up @@ -604,7 +604,8 @@ suite('recur_iterator', function() {
'2015-01-19T08:00:00',
'2015-01-21T08:00:00',
'2015-01-23T08:00:00'
]});
]
});

//Repeat Monthly, the fifth Saturday (BYDAY=5SA)
testRRULE('FREQ=MONTHLY;BYDAY=5SA', {
Expand All @@ -616,8 +617,8 @@ suite('recur_iterator', function() {
'2016-01-30T08:00:00',
'2016-04-30T08:00:00',
'2016-07-30T08:00:00'
]
});
]
});

// Repeat Monthly, the fifth Wednesday every two months (BYDAY=5WE)
testRRULE('FREQ=MONTHLY;INTERVAL=2;BYDAY=5WE', {
Expand Down Expand Up @@ -666,7 +667,7 @@ suite('recur_iterator', function() {
]
});

// monthly, bymonthday
// Last day of the month, monthly.
testRRULE('FREQ=MONTHLY;BYMONTHDAY=-1', {
dtStart: '2015-01-01T08:00:00',
dates: [
Expand All @@ -676,6 +677,32 @@ suite('recur_iterator', function() {
]
});

// Last day of the month, every 3 months.
testRRULE('FREQ=MONTHLY;INTERVAL=3;BYMONTHDAY=-1', {
dtStart: '2022-06-01T08:00:00',
dates: [
'2022-06-30T08:00:00',
'2022-09-30T08:00:00',
'2022-12-31T08:00:00',
'2023-03-31T08:00:00',
'2023-06-30T08:00:00',
'2023-09-30T08:00:00',
]
});

// Second-to-last day of the month, every 3 months.
testRRULE('FREQ=MONTHLY;INTERVAL=3;BYMONTHDAY=-2', {
dtStart: '2022-06-01T08:00:00',
dates: [
'2022-06-29T08:00:00',
'2022-09-29T08:00:00',
'2022-12-30T08:00:00',
'2023-03-30T08:00:00',
'2023-06-29T08:00:00',
'2023-09-29T08:00:00',
]
});

// monthly + by month
testRRULE('FREQ=MONTHLY;BYMONTH=1,3,6,9,12', {
dates: [
Expand All @@ -696,7 +723,7 @@ suite('recur_iterator', function() {
'2015-03-23T08:00:00Z',
'2015-03-27T08:00:00Z',
]
})
});
testRRULE('FREQ=MONTHLY;BYDAY=MO,FR;BYMONTHDAY=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31;COUNT=4', {
dtStart: '2015-04-01T08:00:00Z',
byCount: true,
Expand All @@ -706,7 +733,7 @@ suite('recur_iterator', function() {
'2015-04-17T08:00:00Z',
'2015-04-27T08:00:00Z'
]
})
});
testRRULE('FREQ=MONTHLY;BYDAY=MO,SA;BYMONTHDAY=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31;COUNT=4', {
dtStart: '2015-04-01T08:00:00Z',
byCount: true,
Expand All @@ -716,7 +743,7 @@ suite('recur_iterator', function() {
'2015-04-25T08:00:00Z',
'2015-04-27T08:00:00Z'
]
})
});
testRRULE('FREQ=MONTHLY;BYDAY=SU,FR;BYMONTHDAY=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31;COUNT=9', {
dtStart: '2015-02-28T08:00:00Z',
byCount: true,
Expand All @@ -731,7 +758,7 @@ suite('recur_iterator', function() {
"2015-04-17T08:00:00Z",
"2015-04-19T08:00:00Z"
]
})
});
});

suite('YEARLY', function() {
Expand Down

0 comments on commit 7fb7b51

Please sign in to comment.