From 7c69c6f7f12cd035db57b693bfc411a9130d5d3d Mon Sep 17 00:00:00 2001 From: Morik Date: Sat, 7 Jan 2017 17:22:03 +0100 Subject: [PATCH] Fix cronjob month calculation The current calculation ignores given months, this is fixxed with this pull request. To detect any issues with the new implementation i'll run several tests without any differences with the currently used cronjobs used by the wsc. https://gist.github.com/Morik/27804aaa57916150dd08268cd8e224d8 Running those tests took quite a while but there have been no differences for all calculations without a month selection so this fix should have no problems with them. It also allows some exotic cronjobs like the 29. February etc. --- .../files/lib/util/CronjobUtil.class.php | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/wcfsetup/install/files/lib/util/CronjobUtil.class.php b/wcfsetup/install/files/lib/util/CronjobUtil.class.php index 6cfca4e5e8..489f5067b1 100644 --- a/wcfsetup/install/files/lib/util/CronjobUtil.class.php +++ b/wcfsetup/install/files/lib/util/CronjobUtil.class.php @@ -138,14 +138,30 @@ final class CronjobUtil { * @param array $values */ protected static function calculateTime(array &$values) { - // calculation starts with month, thus start with - // month of $time (if within values) - $currentMonth = gmdate('n', self::$timeBase); - self::findKey($currentMonth, $values['month']); - self::calculateDay($values); } + /** + * Calculates the next month and year to match given criteria. + * + * @param integer $month + * @param integer $year + * @param array $values + */ + protected static function calculateMonth($month, $year, array &$values) { + $index = self::findKey($month, $values['month']); + + // swap to the next year if the next execution month is before the current month + if ($values['month'][$index] < $month) { + $year++; + } + + return [ + 'month' => $values['month'][$index], + 'year' => $year + ]; + } + /** * Calculates the day while adjusting month and year to match given criteria. * @@ -169,6 +185,21 @@ final class CronjobUtil { $month = gmdate('n', $timeBase); $year = gmdate('Y', $timeBase); + // calculate month of next execution and if its not the current one reset previous calculations + $dateMonth = self::calculateMonth($month, $year, $values); + if ($month != $dateMonth['month'] || $year != $dateMonth['year']) { + $day = 1; + $month = $dateMonth['month']; + $year = $dateMonth['year']; + + $timeBase = gmmktime(0, 0, 1, $month, $day, $year); + + if (!$addAnDay) { + self::calculateHour($values, $timeBase); + $addAnDay = true; + } + } + // calculate date of next execution based upon day of week $dateDow = self::calculateDow($month, $year, $values, $day); $dateDowTimestamp = gmmktime(0, 0, 1, $dateDow['month'], $dateDow['day'], $dateDow['year']); @@ -245,7 +276,8 @@ final class CronjobUtil { } // try next month - return self::calculateDow(++$month, $year, $values); + $nextMonth = self::calculateMonth(++$month, $year, $values); + return self::calculateDow($nextMonth['month'], $nextMonth['year'], $values); } /** @@ -271,7 +303,8 @@ final class CronjobUtil { } // try next month - return self::calculateDom(++$month, $year, $values); + $nextMonth = self::calculateMonth(++$month, $year, $values); + return self::calculateDom($nextMonth['month'], $nextMonth['year'], $values); } /** -- 2.20.1