From d8b11d4aaae1e3d2086d51474d74b684ccb381ff Mon Sep 17 00:00:00 2001 From: Gunnar Wrobel Date: Mon, 9 Nov 2009 14:09:21 +0100 Subject: [PATCH] Second attempt at fixing weekly recurrences with several incidences per week. Added a few unit tests as the original variant did not cover all corner cases. --- framework/Date/lib/Horde/Date/Recurrence.php | 57 +++++++--------------- framework/Date/test/Horde/Date/RecurrenceTest.php | 59 +++++++++++++++++++++++ 2 files changed, 77 insertions(+), 39 deletions(-) diff --git a/framework/Date/lib/Horde/Date/Recurrence.php b/framework/Date/lib/Horde/Date/Recurrence.php index 7231669d9..b6e83eaf7 100644 --- a/framework/Date/lib/Horde/Date/Recurrence.php +++ b/framework/Date/lib/Horde/Date/Recurrence.php @@ -401,50 +401,20 @@ class Horde_Date_Recurrence $diff = $start_week->diff($after_week); $recur = $diff + ($diff % ($this->recurInterval * 7)); - if ($this->recurCount && - ceil($recur / 7) / $this->recurInterval >= $this->recurCount) { - return false; - } - if (!$this->hasRecurEnd() && $this->recurCount > 0) { - $start_week_end = clone $start_week; - $start_week_end->mday += 7; + if ($this->hasRecurCount()) { $recurrences = 0; - $total_recurrences_per_week = 0; - $next = clone $start_week; - while ($next->compareDateTime($start_week_end) < 0 - && $next->compareDateTime($after) < 0) { - - if ($this->recurOnDay((int)pow(2, $next->dayOfWeek()))) { - $total_recurrences_per_week++; - if ($next->compareDateTime($this->start) >= 0) - $recurrences++; - } - ++$next->mday; - } - if ($recurrences >= $this->recurCount) - return false; - if ($diff >= $this->recurInterval * 7) { - // calculate the number of weeks between the start and the - // end week - $recurrences += ((int)floor(($diff/($this->recurInterval * 7))) - 1) * $total_recurrences_per_week; - if ($recurrences >= $this->recurCount) - return false; - if ($diff % ($this->recurInterval * 7) == 0) { - // the last week is in the interval - therefore the - // recurrences in the week have to be counted also - $next = clone $after_week; - while ($next->compareDateTime($after_week_end) < 0 - && $next->compareDateTime($after) < 0) { - if ($this->recurOnDay((int)pow(2, $next->dayOfWeek()))) { - $recurrences++; - } - ++$next->mday; + if ($recur > 0) { + $weekdays = $this->recurData; + $total_recurrences_per_week = 0; + while ($weekdays > 0) { + if ($weekdays % 2) { + $total_recurrences_per_week++; } + $weekdays = ($weekdays - ($weekdays % 2)) / 2; } + $recurrences += $total_recurrences_per_week * ($recur / ($this->recurInterval * 7)); } - if ($recurrences >= $this->recurCount) - return false; } $next = clone $start_week; @@ -452,6 +422,15 @@ class Horde_Date_Recurrence while ($next->compareDateTime($after) < 0 && $next->compareDateTime($after_week_end) < 0) { ++$next->mday; + if ($this->hasRecurCount() + && $next->compareDateTime($this->start) >= 0 + && $this->recurOnDay((int)pow(2, $next->dayOfWeek()))) { + $recurrences++; + } + } + if ($this->hasRecurCount() && + $recurrences >= $this->recurCount) { + return false; } if (!$this->hasRecurEnd() || $next->compareDateTime($this->recurEnd) <= 0) { diff --git a/framework/Date/test/Horde/Date/RecurrenceTest.php b/framework/Date/test/Horde/Date/RecurrenceTest.php index 0342bdba0..3cc11fbbe 100644 --- a/framework/Date/test/Horde/Date/RecurrenceTest.php +++ b/framework/Date/test/Horde/Date/RecurrenceTest.php @@ -137,6 +137,21 @@ class Horde_Date_RecurrenceTest extends PHPUnit_Framework_TestCase $this->_getRecurrences($r)); } + public function testWeeklyCountWithMultipleIncidencesPerWeekIfTheFirstIncidenceInThisWeekHasAlreadyPassed() + { + $r = new Horde_Date_Recurrence('2007-02-27 10:00:00'); + $r->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); + $r->setRecurOnDay(Horde_Date::MASK_MONDAY | Horde_Date::MASK_SATURDAY); + $r->setRecurInterval(1); + $r->setRecurCount(3); + $this->assertEquals('W1 MO SA #3', $r->toRRule10($this->ical)); + $this->assertEquals('FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,SA;COUNT=3', $r->toRRule20($this->ical)); + $this->assertEquals(array('2007-03-03 10:00:00', + '2007-03-05 10:00:00', + '2007-03-10 10:00:00',), + $this->_getRecurrences($r)); + } + public function testWeeklyCountWithMultipleIncidencesPerWeek() { $r = new Horde_Date_Recurrence('2007-03-01 10:00:00'); @@ -152,6 +167,50 @@ class Horde_Date_RecurrenceTest extends PHPUnit_Framework_TestCase $this->_getRecurrences($r)); } + public function testWeeklyCountWithMultipleIncidencesPerWeekAndIntervalLargerOne() + { + $r = new Horde_Date_Recurrence('2007-03-01 10:00:00'); + $r->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); + $r->setRecurOnDay(Horde_Date::MASK_THURSDAY | Horde_Date::MASK_SATURDAY); + $r->setRecurInterval(2); + $r->setRecurCount(3); + $this->assertEquals('W2 TH SA #3', $r->toRRule10($this->ical)); + $this->assertEquals('FREQ=WEEKLY;INTERVAL=2;BYDAY=TH,SA;COUNT=3', $r->toRRule20($this->ical)); + $this->assertEquals(array('2007-03-01 10:00:00', + '2007-03-03 10:00:00', + '2007-03-15 10:00:00',), + $this->_getRecurrences($r)); + } + + public function testWeeklyCountWithMultipleIncidencesPerWeekAndLastWeekIsComplete() + { + $r = new Horde_Date_Recurrence('2007-03-01 10:00:00'); + $r->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); + $r->setRecurOnDay(Horde_Date::MASK_THURSDAY | Horde_Date::MASK_SATURDAY); + $r->setRecurInterval(1); + $r->setRecurCount(4); + $this->assertEquals('W1 TH SA #4', $r->toRRule10($this->ical)); + $this->assertEquals('FREQ=WEEKLY;INTERVAL=1;BYDAY=TH,SA;COUNT=4', $r->toRRule20($this->ical)); + $this->assertEquals(array('2007-03-01 10:00:00', + '2007-03-03 10:00:00', + '2007-03-08 10:00:00', + '2007-03-10 10:00:00'), + $this->_getRecurrences($r)); + } + + public function testWeeklyCountWithMultipleIncidencesPerWeekAndCountIsOne() + { + $r = new Horde_Date_Recurrence('2007-03-01 10:00:00'); + $r->setRecurType(Horde_Date_Recurrence::RECUR_WEEKLY); + $r->setRecurOnDay(Horde_Date::MASK_THURSDAY | Horde_Date::MASK_SATURDAY); + $r->setRecurInterval(1); + $r->setRecurCount(1); + $this->assertEquals('W1 TH SA #1', $r->toRRule10($this->ical)); + $this->assertEquals('FREQ=WEEKLY;INTERVAL=1;BYDAY=TH,SA;COUNT=1', $r->toRRule20($this->ical)); + $this->assertEquals(array('2007-03-01 10:00:00'), + $this->_getRecurrences($r)); + } + public function testMonthlyEnd() { $r = new Horde_Date_Recurrence('2007-03-01 10:00:00'); -- 2.11.0