Page MenuHomePhabricator

D16619.diff
No OneTemporary

D16619.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
@@ -23,6 +23,8 @@
private $cursorHour;
private $cursorWeek;
private $cursorDay;
+ private $cursorDayMonth;
+ private $cursorDayYear;
private $cursorMonth;
private $cursorYear;
@@ -322,6 +324,8 @@
// TODO: Figure this out.
$this->cursorWeek = null;
$this->cursorDay = $date->getDay();
+ $this->cursorDayMonth = $date->getMonth();
+ $this->cursorDayYear = $date->getYear();
$this->cursorMonth = $date->getMonth();
$this->cursorYear = $date->getYear();
@@ -594,29 +598,28 @@
$by_monthday = $this->getByMonthDay();
$by_yearday = $this->getByYearDay();
$by_weekno = $this->getByWeekNumber();
+ $by_month = $this->getByMonth();
$week_start = $this->getWeekStart();
while (!$this->setDays) {
$this->nextMonth();
- if ($is_daily || $by_day || $by_monthday || $by_yearday || $by_weekno) {
+ $is_dyanmic = $is_daily
+ || $by_day
+ || $by_monthday
+ || $by_yearday
+ || $by_weekno
+ || ($scale < self::SCALE_DAILY);
+
+ if ($is_dyanmic) {
$weeks = $this->newDaysSet(
- ($is_daily ? $interval : null),
+ ($is_daily ? $interval : 1),
($is_weekly ? $interval : null),
$by_day,
$by_monthday,
$by_yearday,
$by_weekno,
$week_start);
- } else if ($scale < self::SCALE_DAILY) {
- $weeks = $this->newDaysSet(
- 1,
- null,
- array(),
- array(),
- array(),
- array(),
- $week_start);
} else {
// 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
@@ -788,10 +791,11 @@
$by_weekno,
$week_start) {
- $year_map = $this->getYearMap($this->stateYear, $week_start);
$selection = array();
if ($interval_week) {
+ $year_map = $this->getYearMap($this->stateYear, $week_start);
+
while (true) {
// TODO: This is all garbage?
if ($this->cursorWeek > $year_map['weekCount']) {
@@ -811,29 +815,41 @@
$this->cursorWeek += $interval_week;
}
} else {
- $month_idx = $this->stateMonth;
-
if (!$interval_day) {
$interval_day = 1;
}
- // If we have a BYDAY, BYMONTHDAY, BYYEARDAY or BYWEEKNO selector and
- // this isn't the initial month, reset the day cursor to the first of the
- // month to make sure we examine the entire month. If we don't do this,
- // we can have a situation where an event occurs "every Monday in
- // October", but has a start date on the 19th of August, and misses
- // Mondays in October prior to the 19th.
- if ($by_day || $by_monthday || $by_yearday || $by_weekno) {
- if ($this->stateYear !== $this->initialYear ||
- $this->stateMonth !== $this->initialMonth) {
- $this->cursorDay = 1;
+ // If the day cursor is behind the current year and month, we need to
+ // forward it in INTERVAL increments so we end up with the right offset
+ // in the current month.
+ $year_map = $this->getYearMap($this->cursorDayYear, $week_start);
+ while (($this->cursorDayYear < $this->stateYear) ||
+ ($this->cursorDayYear == $this->stateYear &&
+ $this->cursorDayMonth < $this->stateMonth)) {
+ $this->cursorDay += $interval_day;
+ if ($this->cursorDay > $year_map['monthDays'][$this->cursorDayMonth]) {
+ $this->cursorDay -= $year_map['monthDays'][$this->cursorDayMonth];
+ $this->cursorDayMonth++;
+ if ($this->cursorDayMonth > 12) {
+ $this->cursorDayMonth = 1;
+ $this->cursorDayYear++;
+ $year_map = $this->getYearMap($this->cursorDayYear, $week_start);
+ }
}
}
while (true) {
+ $month_idx = $this->stateMonth;
$month_days = $year_map['monthDays'][$month_idx];
if ($this->cursorDay > $month_days) {
$this->cursorDay -= $month_days;
+ $this->cursorDayMonth++;
+ if ($this->cursorDayMonth > 12) {
+ $this->cursorDayMonth = 1;
+ $this->cursorDayYear++;
+ // NOTE: The year map is now out of date, but we're about to break
+ // out of the loop anyway so it doesn't matter.
+ }
break;
}
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
@@ -684,6 +684,69 @@
$expect);
}
+ public function testDailyRecurrenceRules() {
+ $tests = array();
+ $expect = array();
+
+ $tests[] = array();
+ $expect[] = array(
+ '19970902',
+ '19970903',
+ '19970904',
+ );
+
+ $tests[] = array(
+ 'INTERVAL' => 2,
+ );
+ $expect[] = array(
+ '19970902',
+ '19970904',
+ '19970906',
+ );
+
+ $tests[] = array(
+ 'INTERVAL' => 92,
+ );
+ $expect[] = array(
+ '19970902',
+ '19971203',
+ '19980305',
+ );
+
+ $tests[] = array(
+ 'BYMONTH' => array(1, 3),
+ );
+ $expect[] = array(
+ '19980101',
+ '19980102',
+ '19980103',
+ );
+
+ // This is testing that INTERVAL is respected in the presence of a BYMONTH
+ // filter which skips some months
+ $tests[] = array(
+ 'BYMONTH' => array(12),
+ 'INTERVAL' => 17,
+ );
+ $expect[] = array(
+ '19971213',
+ '19971230',
+ '19981205',
+ );
+
+
+
+ $this->assertRules(
+ array(
+ 'FREQ' => 'DAILY',
+ 'COUNT' => 3,
+ 'DTSTART' => '19970902',
+ ),
+ $tests,
+ $expect);
+ }
+
+
private function assertRules(array $defaults, array $tests, array $expect) {
foreach ($tests as $key => $test) {
$options = $test + $defaults;

File Metadata

Mime Type
text/plain
Expires
Sun, Oct 20, 2:54 AM (3 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6715587
Default Alt Text
D16619.diff (6 KB)

Event Timeline