Page MenuHomePhabricator

D16605.id39995.diff
No OneTemporary

D16605.id39995.diff

diff --git a/src/parser/calendar/data/PhutilCalendarRecurrenceRule.php b/src/parser/calendar/data/PhutilCalendarRecurrenceRule.php
--- a/src/parser/calendar/data/PhutilCalendarRecurrenceRule.php
+++ b/src/parser/calendar/data/PhutilCalendarRecurrenceRule.php
@@ -127,7 +127,7 @@
if (empty($map[$frequency])) {
throw new Exception(
pht(
- 'RRULE FREQUENCY "%s" is invalid. Valid frequencies are: %s.',
+ 'RRULE FREQ "%s" is invalid. Valid frequencies are: %s.',
$frequency,
implode(', ', array_keys($map))));
}
@@ -489,6 +489,7 @@
$by_yearday = $this->getByYearDay();
$by_weekno = $this->getByWeekNumber();
$by_setpos = $this->getBySetPosition();
+ $week_start = $this->getWeekStart();
while (!$this->setDays) {
$this->nextMonth();
@@ -501,7 +502,7 @@
$by_monthday,
$by_yearday,
$by_weekno,
- $this->getWeekStart());
+ $week_start);
} else if ($scale < self::SCALE_DAILY) {
$weeks = $this->newDaysSet(
1,
@@ -510,11 +511,21 @@
array(),
array(),
array(),
- $this->getWeekStart());
+ $week_start);
} else {
- $weeks = array(
- array($this->cursorDay),
- );
+ // The cursor day may not actually exist in the current month, so
+ // make sure the day is valid before we generate a set which contains
+ // it.
+ $year_map = $this->getYearMap($this->stateYear, $week_start);
+ if ($this->cursorDay > $year_map['monthDays'][$this->stateMonth]) {
+ $weeks = array(
+ array(),
+ );
+ } else {
+ $weeks = array(
+ array($this->cursorDay),
+ );
+ }
}
// Apply weekly BYSETPOS, if one exists.
@@ -578,6 +589,7 @@
}
protected function nextYear() {
+
$this->stateYear = $this->cursorYear;
$frequency = $this->getFrequency();
@@ -680,7 +692,7 @@
}
$last = last($selection);
- if ($last['month'] > $this->cursorMonth) {
+ if ($last['month'] > $this->stateMonth) {
break;
}
@@ -688,7 +700,7 @@
}
} else {
$calendar = $year_map['calendar'];
- $month_idx = $this->cursorMonth;
+ $month_idx = $this->stateMonth;
if (!$interval_day) {
$interval_day = 1;
@@ -712,7 +724,7 @@
$weeks = array();
foreach ($selection as $key => $info) {
- if ($info['month'] != $this->cursorMonth) {
+ if ($info['month'] != $this->stateMonth) {
continue;
}
diff --git a/src/parser/calendar/data/__tests__/PhutilCalendarRecurrenceRuleTestCase.php b/src/parser/calendar/data/__tests__/PhutilCalendarRecurrenceRuleTestCase.php
--- a/src/parser/calendar/data/__tests__/PhutilCalendarRecurrenceRuleTestCase.php
+++ b/src/parser/calendar/data/__tests__/PhutilCalendarRecurrenceRuleTestCase.php
@@ -102,4 +102,71 @@
pht('Secondly event with many constraints.'));
}
+ public function testYearlyRecurrenceRules() {
+ $tests = array();
+ $expect = array();
+
+ $tests[] = array();
+ $expect[] = array(
+ '19970902',
+ '19980902',
+ '19990902',
+ );
+
+ $tests[] = array(
+ 'INTERVAL' => 2,
+ );
+ $expect[] = array(
+ '19970902',
+ '19990902',
+ '20010902',
+ );
+
+ $tests[] = array(
+ 'DTSTART' => '20000229',
+ );
+ $expect[] = array(
+ '20000229',
+ '20040229',
+ '20080229',
+ );
+
+ $this->assertRules(
+ array(
+ 'FREQ' => 'YEARLY',
+ 'COUNT' => 3,
+ 'DTSTART' => '19970902',
+ ),
+ $tests,
+ $expect);
+ }
+
+ private function assertRules(array $defaults, array $tests, array $expect) {
+ foreach ($tests as $key => $test) {
+ $options = $test + $defaults;
+
+ $start = PhutilCalendarAbsoluteDateTime::newFromISO8601(
+ $options['DTSTART']);
+
+ $rrule = id(new PhutilCalendarRecurrenceRule())
+ ->setStartDateTime($start)
+ ->setFrequency($options['FREQ']);
+
+ $interval = idx($options, 'INTERVAL');
+ if ($interval) {
+ $rrule->setInterval($interval);
+ }
+
+ $set = id(new PhutilCalendarRecurrenceSet())
+ ->addSource($rrule);
+
+ $result = $set->getEventsBetween(null, null, $options['COUNT']);
+
+ $this->assertEqual(
+ $expect[$key],
+ mpull($result, 'getISO8601'));
+ }
+ }
+
+
}

File Metadata

Mime Type
text/plain
Expires
Tue, Mar 25, 5:09 PM (3 d, 13 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7664485
Default Alt Text
D16605.id39995.diff (4 KB)

Event Timeline