From 267b237d8981d143be184ea627ac1132673558b6 Mon Sep 17 00:00:00 2001 From: Christopher Szu Date: Fri, 29 Dec 2023 11:07:30 +0800 Subject: [PATCH] make test pass from both sides --- lib/Recur/RRuleIterator.php | 13 ++++++++++++- tests/VObject/Recur/FastForwardToEndTest.php | 3 +++ tests/VObject/Recur/RRuleIteratorTest.php | 14 +++++++++++--- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/Recur/RRuleIterator.php b/lib/Recur/RRuleIterator.php index 0b3140bb0..ecf1affeb 100644 --- a/lib/Recur/RRuleIterator.php +++ b/lib/Recur/RRuleIterator.php @@ -28,6 +28,8 @@ class RRuleIterator implements \Iterator */ public const dateUpperLimit = 253402300799; + private bool $yearlySkipUpperLimit; + /** * Creates the Iterator. * @@ -35,11 +37,12 @@ class RRuleIterator implements \Iterator * * @throws InvalidDataException */ - public function __construct($rrule, \DateTimeInterface $start) + public function __construct($rrule, \DateTimeInterface $start, bool $yearlySkipUpperLimit = true) { $this->startDate = $start; $this->parseRRule($rrule); $this->currentDate = clone $this->startDate; + $this->yearlySkipUpperLimit = $yearlySkipUpperLimit; } /* Implementation of the Iterator interface {{{ */ @@ -823,6 +826,14 @@ protected function nextYearly($amount = 1): void (int) $currentMonth, (int) $currentDayOfMonth ); + + // To prevent running this forever (better: until we hit the max date of DateTimeImmutable) we simply + // stop at 9999-12-31. Looks like the year 10000 problem is not solved in php .... + if (!$this->yearlySkipUpperLimit && ($this->currentDate->getTimestamp() > self::dateUpperLimit)) { + $this->currentDate = null; + + return; + } } // If we made it here, it means we got a valid occurrence diff --git a/tests/VObject/Recur/FastForwardToEndTest.php b/tests/VObject/Recur/FastForwardToEndTest.php index 1073a95df..0b94f3945 100644 --- a/tests/VObject/Recur/FastForwardToEndTest.php +++ b/tests/VObject/Recur/FastForwardToEndTest.php @@ -229,6 +229,9 @@ public function testFastForwardToEndUntilMonthly31thDay() $this->assertEquals($expected, $rrule->current()->getTimestamp()); } + /** + * @medium + */ public function testFastForwardToEndCountMonthlyAdvanced() { $startDate = new \DateTime('1970-01-31 00:00:00', new \DateTimeZone('America/New_York')); diff --git a/tests/VObject/Recur/RRuleIteratorTest.php b/tests/VObject/Recur/RRuleIteratorTest.php index 3384506f5..75222f217 100644 --- a/tests/VObject/Recur/RRuleIteratorTest.php +++ b/tests/VObject/Recur/RRuleIteratorTest.php @@ -1052,7 +1052,14 @@ public function testYearlyBySetPosLoop(): void 'FREQ=YEARLY;BYMONTH=5;BYSETPOS=3;BYMONTHDAY=3', '2022-03-03 15:45:00', [], - 'yearly', null, 1, null, '2022-05-01' + 'yearly', + null, + 1, + null, + '2022-05-01', + 'UTC', + false, + false, ); } @@ -1245,10 +1252,11 @@ public function parse( $expectedUntil = null, string $fastForward = null, string $tz = 'UTC', - bool $runTillTheEnd = false + bool $runTillTheEnd = false, + bool $yearlySkipUpperLimit = true ): void { $dt = new \DateTime($start, new \DateTimeZone($tz)); - $parser = new RRuleIterator($rule, $dt); + $parser = new RRuleIterator($rule, $dt, $yearlySkipUpperLimit); $this->assertEquals($expectedFreq, $parser->getFrequency()); $this->assertEquals($expectedCount, $parser->getCount());