Skip to content

Commit

Permalink
Improve fast forward performance
Browse files Browse the repository at this point in the history
  • Loading branch information
KAYLukas committed Dec 7, 2018
1 parent 2089c44 commit a00a460
Showing 1 changed file with 87 additions and 45 deletions.
132 changes: 87 additions & 45 deletions lib/Recur/RRuleIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,30 +85,27 @@ public function rewind()

/**
* Goes on to the next iteration.
* @param int $amount
*/
public function next()
public function next($amount = 1)
{
// Otherwise, we find the next event in the normal RRULE
// sequence.
switch ($this->frequency) {
case 'hourly':
$this->nextHourly();
case 'hourly' :
$this->nextHourly($amount);
break;

case 'daily':
$this->nextDaily();
case 'daily' :
$this->nextDaily($amount);
break;

case 'weekly':
$this->nextWeekly();
case 'weekly' :
$this->nextWeekly($amount);
break;

case 'monthly':
$this->nextMonthly();
case 'monthly' :
$this->nextMonthly($amount);
break;

case 'yearly':
$this->nextYearly();
case 'yearly' :
$this->nextYearly($amount);
break;
}
++$this->counter;
Expand All @@ -134,9 +131,49 @@ public function isInfinite()
*/
public function fastForward(DateTimeInterface $dt)
{
if (!isset($this->count)) {
do {
$diff = $this->currentDate->diff($dt);
switch ($this->frequency) {
case 'hourly' :
$i = $diff->days * 24;
break;
case 'daily' :
$i = $diff->days;
break;
case 'weekly' :
$i = $diff->days / 7;
break;
case 'monthly' :
$i = $diff->days / 30;
break;
case 'yearly' :
$i = $diff->days / 365;
break;
}
$i /= $this->interval;
$i /= 4;
$i = floor($i);
$i = max(1, $i);
do {
$previousDate = clone $this->currentDate;
$this->next($i);
} while ($this->valid() && $this->currentDate < $dt);

$this->currentDate = $previousDate;
// do one step to avoid deadlock
$this->next();
} while ($i > 5 && $this->valid() && $this->currentDate < $dt);
}

while ($this->valid() && $this->currentDate < $dt) {
$this->next();
}

if (!isset($this->count)) {
// We don't know the counter at this point anymore
$this->counter = NAN;
}
}

/**
Expand Down Expand Up @@ -306,19 +343,18 @@ public function fastForward(DateTimeInterface $dt)
/**
* Does the processing for advancing the iterator for hourly frequency.
*/
protected function nextHourly()
protected function nextHourly($amount = 1)
{
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' hours');
$this->currentDate = $this->currentDate->modify('+'.$amount * $this->interval.' hours');
}

/**
* Does the processing for advancing the iterator for daily frequency.
*/
protected function nextDaily()
protected function nextDaily($amount = 1)
{
if (!$this->byHour && !$this->byDay) {
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' days');

$this->currentDate = $this->currentDate->modify('+'.$amount * $this->interval.' days');
return;
}

Expand All @@ -338,14 +374,17 @@ protected function nextDaily()
if ($this->byHour) {
if ('23' == $this->currentDate->format('G')) {
// to obey the interval rule
$this->currentDate = $this->currentDate->modify('+'.$this->interval - 1 .' days');
$this->currentDate = $this->currentDate->modify('+'.(($amount * $this->interval) - 1).' days');
$amount = 1;
}

$this->currentDate = $this->currentDate->modify('+1 hours');
} else {
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' days');
$this->currentDate = $this->currentDate->modify('+'.($amount * $this->interval).' days');
$amount = 1;
}


// Current month of the year
$currentMonth = $this->currentDate->format('n');

Expand All @@ -364,11 +403,10 @@ protected function nextDaily()
/**
* Does the processing for advancing the iterator for weekly frequency.
*/
protected function nextWeekly()
{
if (!$this->byHour && !$this->byDay) {
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' weeks');
protected function nextWeekly($amount = 1) {

if (!$this->byHour && !$this->byDay) {
$this->currentDate = $this->currentDate->modify('+' .($amount * $this->interval).' weeks');
return;
}

Expand Down Expand Up @@ -397,9 +435,9 @@ protected function nextWeekly()
$currentHour = (int) $this->currentDate->format('G');

// We need to roll over to the next week
if ($currentDay === $firstDay && (!$this->byHour || '0' == $currentHour)) {
$this->currentDate = $this->currentDate->modify('+'.$this->interval - 1 .' weeks');

if ($currentDay === $firstDay && (!$this->byHour || $currentHour == '0')) {
$this->currentDate = $this->currentDate->modify('+'.(($amount * $this->interval) - 1).' weeks');
$amount = 1;
// We need to go to the first day of this week, but only if we
// are not already on this first day of this week.
if ($this->currentDate->format('w') != $firstDay) {
Expand All @@ -414,7 +452,7 @@ protected function nextWeekly()
/**
* Does the processing for advancing the iterator for monthly frequency.
*/
protected function nextMonthly()
protected function nextMonthly($amount = 1)
{
$currentDayOfMonth = $this->currentDate->format('j');
$currentHourOfMonth = $this->currentDate->format('G');
Expand All @@ -425,9 +463,9 @@ protected function nextMonthly()
// occur to the next month. We Must skip these invalid
// entries.
if ($currentDayOfMonth < 29) {
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' months');
$this->currentDate = $this->currentDate->modify('+'.($amount * $this->interval).' months');
} else {
$increase = 0;
$increase = $amount - 1;
do {
++$increase;
$tempDate = clone $this->currentDate;
Expand All @@ -443,7 +481,7 @@ protected function nextMonthly()
$occurrences = $this->getMonthlyOccurrences();

foreach ($occurrences as $occurrence) {
// The first occurrence thats higher than the current
// The first occurrence that's higher than the current
// day of the month wins.
if ($occurrence[0] > $currentDayOfMonth) {
break 2;
Expand All @@ -469,13 +507,14 @@ protected function nextMonthly()
// If we made it all the way here, it means there were no
// valid occurrences, and we need to advance to the next
// month.
//
// This line does not currently work in hhvm. Temporary workaround
// follows:
// $this->currentDate->modify('first day of this month');
$this->currentDate = new DateTimeImmutable($this->currentDate->format('Y-m-1 H:i:s'), $this->currentDate->getTimezone());
$this->currentDate = $this->currentDate->setDate(
(int) $this->currentDate->format('Y'),
(int) $this->currentDate->format('n'),
1
);
// end of workaround
$this->currentDate = $this->currentDate->modify('+ '.$this->interval.' months');
$this->currentDate = $this->currentDate->modify('+ '.($amount * $this->interval).' months');
$amount = 1;

// This goes to 0 because we need to start counting at the
// beginning.
Expand All @@ -495,10 +534,10 @@ protected function nextMonthly()
/**
* Does the processing for advancing the iterator for yearly frequency.
*/
protected function nextYearly()
protected function nextYearly($amount = 1)
{
$currentMonth = $this->currentDate->format('n');
$currentYear = $this->currentDate->format('Y');
$currentMonth = $this->currentDate->format('n');
$currentDayOfMonth = $this->currentDate->format('j');
$currentHourOfMonth = $this->currentDate->format('G');
$currentMinuteOfMonth = $this->currentDate->format('i');
Expand Down Expand Up @@ -562,7 +601,8 @@ protected function nextYearly()
}

// if there is no date found, check the next year
$currentYear += $this->interval;
$currentYear += $amount * $this->interval;
$amount = 1;
}
}

Expand Down Expand Up @@ -604,12 +644,13 @@ protected function nextYearly()
}

// if there is no date found, check the next year
$currentYear += $this->interval;
$currentYear += ($amount * $this->interval);
$amount = 1;
}
}

// The easiest form
$this->currentDate = $this->currentDate->modify('+'.$this->interval.' years');
$this->currentDate = $this->currentDate->modify('+'.($amount * $this->interval).' years');

return;
}
Expand Down Expand Up @@ -656,7 +697,8 @@ protected function nextYearly()
do {
++$currentMonth;
if ($currentMonth > 12) {
$currentYear += $this->interval;
$currentYear += ($amount * $this->interval);
$amount = 1;
$currentMonth = 1;
}
} while (!in_array($currentMonth, $this->byMonth));
Expand Down

0 comments on commit a00a460

Please sign in to comment.