diff --git a/lib/Recur/RRuleIterator.php b/lib/Recur/RRuleIterator.php index b003dcd60..da788a126 100644 --- a/lib/Recur/RRuleIterator.php +++ b/lib/Recur/RRuleIterator.php @@ -24,6 +24,13 @@ */ class RRuleIterator implements Iterator { + /** + * Constant denoting the upper limit on how long into the future + * we want to iterate. The value is a unix timestamp and currently + * corresponds to the datetime 9999-12-31 11:59:59 UTC. + */ + const dateUpperLimit = 253402300799; + /** * Creates the Iterator. * @@ -366,6 +373,12 @@ protected function nextDaily() // Current hour of the day $currentHour = $this->currentDate->format('G'); + + if ($this->currentDate->getTimestamp() > self::dateUpperLimit) { + $this->currentDate = null; + + return; + } } while ( ($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours)) || @@ -486,7 +499,7 @@ protected function nextMonthly() // 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->currentDate->getTimestamp() > 253402300799) { + if ($this->currentDate->getTimestamp() > self::dateUpperLimit) { $this->currentDate = null; return; @@ -661,7 +674,7 @@ protected function nextYearly() // 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->currentDate->getTimestamp() > 253402300799) { + if ($this->currentDate->getTimestamp() > self::dateUpperLimit) { $this->currentDate = null; return; diff --git a/tests/VObject/Recur/RRuleIteratorTest.php b/tests/VObject/Recur/RRuleIteratorTest.php index 23b1396b9..4c9107ee5 100644 --- a/tests/VObject/Recur/RRuleIteratorTest.php +++ b/tests/VObject/Recur/RRuleIteratorTest.php @@ -147,6 +147,24 @@ public function testDailyByMonth() ); } + /** + * This test can take some seconds to complete. + * The "large" annotation means phpunit will let it run for + * up to 60 seconds by default. + * + * @large + */ + public function testDailyBySetPosLoop() + { + $this->parse( + 'FREQ=DAILY;INTERVAL=7;BYDAY=MO', + '2022-03-15', + [ + ], + '2022-05-01' + ); + } + public function testWeekly() { $this->parse( @@ -825,6 +843,13 @@ public function testYearlyByMonthLoop() ); } + /** + * This test can take some seconds to complete. + * The "large" annotation means phpunit will let it run for + * up to 60 seconds by default. + * + * @large + */ public function testYearlyBySetPosLoop() { $this->parse(