Skip to content
Snippets Groups Projects

Fix/22152 scheduling next execution calculation error

1 file
+ 281
160
Compare changes
  • Side-by-side
  • Inline
@@ -199,8 +199,7 @@ class scheduling
$this->removeServiceTokens();
$scheduling->lastExecution = \laabs::newDateTime(null, 'UTC');
$frequency = explode(";", $scheduling->frequency);
$scheduling->nextExecution = $this->nextExecution($frequency);
$scheduling->nextExecution = $this->nextExecution($scheduling->frequency, $scheduling->lastExecution);
if ($success) {
$scheduling->status = "scheduled";
@@ -243,8 +242,8 @@ class scheduling
}
if (empty($scheduling->nextExecution)) {
$frequency = explode(";", $scheduling->frequency);
$scheduling->nextExecution = $this->nextExecution($frequency);
$prev = \laabs::newDateTime(null, 'UTC');
$scheduling->nextExecution = $this->nextExecution($scheduling->frequency, $prev);
$this->sdoFactory->update($scheduling, "batchProcessing/scheduling");
}
@@ -289,195 +288,318 @@ class scheduling
}
/**
* Date of next execution
*
* @param array $frequency
* @return DateTime
* Parse scheduling frequency
* @param string $frequency
* @return object
*/
private function nextExecution($frequency)
public function parseScheduling(string $frequency)
{
$currentDate = \laabs::newDateTime(null, 'UTC');
$endDate = \laabs::newDateTime(null, 'UTC');
$UTC_Offset = date('Z');
$frequency = explode(";", $frequency);
$H_Offset = $UTC_Offset/3600;
/**
* [0] start Minutes
* [1] start Hours
* [2] Day week ex : Fri
* [3] Day month ex : 1,2,3
* [4] month ex : apr, may, jun
* [5] number of case 7
* [6] Frequence unity minute (m) or hour (h)
* [7] end Minutes
* [8] end Hours
* [0] start time Minutes
* [1] start time Hours
* [2] Weekly : Days of week ex Fri
* [3] Monthly/Yearly : Days of month ex 1,2,3
* [4] Yealy : Month ex apr, may, jun
* [5] Repeat : Frequency
* [6] Repeat : Frequency unit minute (m) or hour (h)
* [7] Repeat : end time Minutes
* [8] Repeat : end time Hours
* Exemple frequency = [0;18;"Thu";"";"";"5";"m";"0";"20"];
* Thursday 18h -> 20h every 5 Minutes
*/
if (!empty($frequency[1])) {
$frequency[1] -= $H_Offset;
$scheduler = (object) [];
$scheduler->now = \laabs::newDateTime(null, 'UTC');
$scheduler->next = clone($scheduler->now);
$scheduler->startMin = $frequency[0];
$scheduler->startHour = $frequency[1];
$scheduler->type = 'daily';
$scheduler->repeat = false;
if (!empty($frequency[2])) {
$scheduler->type = 'weekly';
$scheduler->weekDays = \laabs\explode(",", $frequency[2]);
}
if (!empty($frequency[8] && $frequency[8] != "00")) {
$frequency[8] -= $H_Offset;
if (!empty($frequency[3]) && !empty($frequency[4])) {
$scheduler->type = 'yearly';
$scheduler->monthDays = \laabs\explode(",", $frequency[3]);
$scheduler->months = \laabs\explode(",", $frequency[4]);
}
if (intval($frequency[1]) < 0) {
$frequency[1] = 24 + intval($frequency[1]);
} elseif (intval($frequency[1]) >= 24) {
$frequency[1] = intval($frequency[1]) - 24;
if (!empty($frequency[3]) && empty($frequency[4])) {
$scheduler->type = 'monthly';
$scheduler->monthDays = \laabs\explode(",", $frequency[3]);
}
if (intval($frequency[8]) < 0) {
$frequency[8] = 24 + intval($frequency[8]);
} elseif (intval($frequency[8]) >= 24) {
$frequency[8] = intval($frequency[8]) - 24;
if (!empty($frequency[5]) && !empty($frequency[6])) {
$scheduler->repeat = true;
$scheduler->repeatInterval = strtoupper("PT".$frequency[5].$frequency[6]);
$scheduler->repeatEndMin = $frequency[7];
$scheduler->repeatEndHour = $frequency[8];
}
return $scheduler;
}
/**
* Date of next execution
*
* @param string $frequency
* @param dateTime $prev
* @return DateTime
*/
public function nextExecution($frequency)
{
$UTC_Offset = date('Z');
$H_Offset = $UTC_Offset/3600;
$scheduler = $this->parseScheduling($frequency);
// Apply time offset to start and end hours
if (!empty($scheduler->startHour)) {
$scheduler->startHour -= $H_Offset;
}
if (intval($scheduler->startHour) < 0) {
$scheduler->startHour = 24 + intval($scheduler->startHour);
} elseif (intval($scheduler->startHour) >= 24) {
$scheduler->startHour = intval($scheduler->startHour) - 24;
}
if ($frequency[6] != "") {
if ($frequency[2] == "" && $frequency[3] == "") {
$timeAdd = strtoupper("PT".$frequency[5].$frequency[6]);
$currentDate->add(new \DateInterval($timeAdd));
if (($frequency[7] != "" && $frequency[8] != "") && ($frequency[7] != "00" && $frequency[8] != "00")) {
$endDate->setTime($frequency[8], $frequency[7], "0");
} else {
$endDate->add(new \DateInterval("P1D"));
$endDate->setTime("0", "0", "0");
}
// Repeat
if ($scheduler->repeat) {
if (!empty($scheduler->repeatEndHour && $scheduler->repeatEndHour != "00")) {
$scheduler->repeatEndHour -= $H_Offset;
}
if (intval($scheduler->repeatEndHour) < 0) {
$scheduler->repeatEndHour = 24 + intval($scheduler->repeatEndHour);
} elseif (intval($scheduler->repeatEndHour) >= 24) {
$scheduler->repeatEndHour = intval($scheduler->repeatEndHour) - 24;
}
return $this->repetition($scheduler);
} else {
return $this->noRepetition($scheduler);
}
$interval = $currentDate->diff($endDate, false);
return $scheduler->next;
}
protected function noRepetition($scheduler)
{
switch ($scheduler->type) {
case 'daily':
return $this->dailyNoRepetition($scheduler);
if ($interval->invert == 0) {
return $currentDate;
} else {
$endDate->add(new \DateInterval("P1D"));
$endDate->setTime($frequency[1], $frequency[0], "0");
case 'weekly':
return $this->weeklyNoRepetition($scheduler);
return $endDate;
}
case 'monthly':
return $this->monthlyNoRepetition($scheduler);
case 'yearly':
return $this->yearlyNoRepetition($scheduler);
}
}
protected function dailyNoRepetition($scheduler)
{
// Set daily time to next execution
$next = \laabs::newDateTime('today', 'UTC');
$next->setTime($scheduler->startHour, $scheduler->startMin, "0");
// If in past, add one day
if ($scheduler->now->diff($next)->invert == 1) {
$next->add(new \DateInterval("P1D"));
}
return $next;
}
protected function weeklyNoRepetition($scheduler)
{
$next = null;
foreach ($scheduler->weekDays as $weekDay) {
$nextWeekDay = \laabs::newDateTime($weekDay, 'UTC');
$nextWeekDay->setTime($scheduler->startHour, $scheduler->startMin, '0');
// If in past today, continue
if ($scheduler->now->diff($nextWeekDay)->invert == 1) {
continue;
}
// No date found yet OR date is closer from now than previously selected one, select new date
if (!$next || $next->diff($nextWeekDay)->invert == 1) {
$next = $nextWeekDay;
}
}
if (!$next) {
$next = \laabs::newDateTime('next '.$scheduler->weekDays[0], 'UTC');
$next->setTime($scheduler->startHour, $scheduler->startMin, '0');
}
return $next;
}
protected function monthlyNoRepetition($scheduler)
{
$next = $this->nextDayOfMonth($scheduler->monthDays);
$next->setTime($scheduler->startHour, $scheduler->startMin, "0");
return $next;
}
protected function yearlyNoRepetition($scheduler)
{
$next = clone($scheduler->prev);
if (count($scheduler->monthDays) == 1) {
$next->add(new \DateInterval("P1M"));
$next->setTime($scheduler->startHour, $scheduler->startMin, "0");
} else {
$next = $this->nextDayOfMonth($scheduler->monthDays);
$next->setTime($scheduler->startHour, $scheduler->startMin, "0");
}
$currentMonth = $next->format("m");
$monthInterval = $this->getNextMonthInterval($currentMonth, $scheduler->months);
$next->add(new \DateInterval("P".$monthInterval."M"));
return $next;
}
protected function repetition($scheduler)
{
switch ($scheduler->type) {
case 'daily':
return $this->dailyRepetition($scheduler);
case 'weekly':
return $this->weeklyRepetition($scheduler);
case 'monthly':
return $this->monthlyRepetition($scheduler);
case 'yearly':
return $this->yearlyRepetition($scheduler);
}
}
protected function dailyRepetition($scheduler)
{
$prev = $scheduler->prev;
$next = clone($scheduler->prev);
$prev->add(new \DateInterval($scheduler->repeatInterval));
if ($scheduler->repeatEndMin != "" && $scheduler->repeatEndHour != ""
&& $scheduler->repeatEndMin != "00" && $scheduler->repeatEndHour != "00") {
$next->setTime($scheduler->repeatEndHour, $scheduler->repeatEndMin, "0");
} else {
$next->add(new \DateInterval("P1D"));
$next->setTime("0", "0", "0");
}
$interval = $prev->diff($next);
if ($interval->invert == 0) {
return $prev;
} else {
$next->add(new \DateInterval("P1D"));
$next->setTime($scheduler->startHour, $scheduler->startMin, "0");
return $next;
}
}
protected function weeklyRepetition($scheduler)
{
$prev = $scheduler->prev;
$next = clone($scheduler->prev);
$prev->add(new \DateInterval($scheduler->repeatInterval));
if ($scheduler->repeatEndMin != "" && $scheduler->repeatEndHour != ""
&& $scheduler->repeatEndMin != "00" && $scheduler->repeatEndHour != "00") {
$next->setTime($scheduler->repeatEndHour, $scheduler->repeatEndMin, "0");
} else {
$next->add(new \DateInterval("P7D"));
$next->setTime("0", "0", "0");
}
$interval = $prev->diff($next);
if ($interval->invert == 0) {
return $prev;
} else {
if (sizeof($scheduler->weekDays) == 1) {
$next->add(new \DateInterval("P7D"));
$next->setTime($scheduler->startHour, $scheduler->startMin, "0");
} else {
if ($frequency[2] != "") {
$daysWeek = explode(",", $frequency[2]);
$timeAdd = strtoupper("PT".$frequency[5].$frequency[6]);
$currentDate->add(new \DateInterval($timeAdd));
if ($frequency[7] != "" && $frequency[8] != "" && ($frequency[7] != "00" && $frequency[8] != "00")) {
$endDate->setTime($frequency[8], $frequency[7], "0");
} else {
$endDate->add(new \DateInterval("P1D"));
$endDate->setTime("0", "0", "0");
}
$interval = $currentDate->diff($endDate, false);
if ($interval->invert == 0) {
return $currentDate;
} else {
if (sizeof($daysWeek) == 1) {
$endDate->add(new \DateInterval("P7D"));
$endDate->setTime($frequency[1], $frequency[0], "0");
} else {
$endDate = $this->nextDayOfWeek($daysWeek, $currentDate);
$endDate->setTime($frequency[1], $frequency[0], "0");
}
return $endDate;
}
} else {
$dayMonths = explode(",", $frequency[3]);
$timeAdd = strtoupper("PT".$frequency[5].$frequency[6]);
$currentDate->add(new \DateInterval($timeAdd));
if ($frequency[7] != "" && $frequency[8] != "" && ($frequency[7] != "00" && $frequency[8] != "00")) {
$endDate->setTime($frequency[8], $frequency[7], "0");
} else {
$endDate->add(new \DateInterval("P1M"));
$endDate->setTime("0", "0", "0");
}
$interval = $currentDate->diff($endDate, false);
if ($interval->invert == 0) {
return $currentDate;
} else {
if (count($dayMonths) == 1) {
$endDate->add(new \DateInterval("P1M"));
$endDate->setTime($frequency[1], $frequency[0], "0");
} else {
$endDate = $this->nextDayOfMonth($dayMonths);
$endDate->setTime($frequency[1], $frequency[0], "0");
}
if ($frequency[4] != "") {
$currentMonth = $endDate->format("m");
$monthInterval = $this->getNextMonthInterval($currentMonth, $frequency[4]);
$endDate->add(new \DateInterval("P".$monthInterval."M"));
}
return $endDate;
}
}
$next = $this->nextDayOfWeek($scheduler->weekDays, $scheduler->prev);
$next->setTime($scheduler->startHour, $scheduler->startMin, "0");
}
return $next;
}
}
protected function monthlyRepetition($scheduler)
{
$prev = $scheduler->prev;
$next = clone($scheduler->prev);
$prev->add(new \DateInterval($scheduler->repeatInterval));
if ($scheduler->repeatEndMin != "" && $scheduler->repeatEndHour != "" && ($scheduler->repeatEndMin != "00" && $scheduler->repeatEndHour != "00")) {
$next->setTime($scheduler->repeatEndHour, $scheduler->repeatEndMin, "0");
} else {
if ($frequency[2] != "") {
$daysWeek = explode(",", $frequency[2]);
if (count($daysWeek) == 1) {
$endDate->add(new \DateInterval("P7D"));
$endDate->setTime($frequency[1], $frequency[0], "0");
} else {
$endDate = $this->nextDayOfWeek($daysWeek, $currentDate);
$endDate->setTime($frequency[1], $frequency[0], "0");
}
} elseif ($frequency[3] != "" && $frequency[4] != "") {
$dayMonths = explode(",", $frequency[3]);
if (count($dayMonths) == 1) {
$endDate->add(new \DateInterval("P1M"));
$endDate->setTime($frequency[1], $frequency[0], "0");
} else {
$endDate = $this->nextDayOfMonth($dayMonths);
$endDate->setTime($frequency[1], $frequency[0], "0");
}
$next->add(new \DateInterval("P1M"));
$next->setTime("0", "0", "0");
}
$interval = $prev->diff($next);
$currentMonth = $endDate->format("m");
$monthInterval = $this->getNextMonthInterval($currentMonth, $frequency[4]);
$endDate->add(new \DateInterval("P".$monthInterval."M"));
} elseif ($frequency[3] != "") {
$dayMonths = explode(",", $frequency[3]);
if (count($dayMonths) == 1) {
$endDate->add(new \DateInterval("P1M"));
$endDate->setTime($frequency[1], $frequency[0], "0");
} else {
$endDate = $this->nextDayOfMonth($dayMonths);
$endDate->setTime($frequency[1], $frequency[0], "0");
}
if ($interval->invert == 0) {
return $prev;
} else {
if (count($scheduler->monthDays) == 1) {
$next->add(new \DateInterval("P1M"));
$next->setTime($scheduler->startHour, $scheduler->startMin, "0");
} else {
$endDate->add(new \DateInterval("P1D"));
$endDate->setTime($frequency[1], $frequency[0], "0");
$next = $this->nextDayOfMonth($scheduler->monthDays);
$next->setTime($scheduler->startHour, $scheduler->startMin, "0");
}
return $endDate;
if ($scheduler->months != "") {
$currentMonth = $next->format("m");
$monthInterval = $this->getNextMonthInterval($currentMonth, $scheduler->months);
$next->add(new \DateInterval("P".$monthInterval."M"));
}
return $next;
}
}
/**
* Next day of execution (Week)
*
* @param array $daysWeek
* @param Datetime $currentDate
* @param object $scheduler
* @return DateTime
*/
private function nextDayOfWeek($daysWeek, $currentDate)
private function nextDayOfWeek($scheduler)
{
$currentTime = strtotime($currentDate->format("Y-m-d\TH:i:s"));
$nextDayTime = 0;
foreach ($daysWeek as $day) {
$dayTime = strtotime($day.",".$currentDate->format("Y-m-d\TH:i:s"));
$nextDay = strtotime($weekDay.",".$scheduler->startHour->format("Y-m-d\TH:i:s"));
if ($dayTime != $currentTime) {
if (!$nextDayTime || $dayTime < $nextDayTime) {
$nextDayTime = $dayTime;
}
}
}
$nextDate = \laabs::newDateTime('UTC');
$nextDate = \laabs::newDateTime(null, 'UTC');
$nextDate->setTimestamp($nextDayTime);
return $nextDate;
@@ -493,7 +615,7 @@ class scheduling
{
$lastDayOfMonth = date('t', strtotime('today'));
$currentDayNum = strtoupper(date("d"));
$endDate = \laabs::newDateTime('UTC');
$endDate = \laabs::newDateTime(null, 'UTC');
$totalMore = 0;
$totalLess = 0;
@@ -531,13 +653,12 @@ class scheduling
* Get positive interval of next month in frequency
*
* @param int $currentMonth The numerical current month
* @param string $frequency Months in string with comma separator
* @param array $months Months
*
* @return int The interval between the current month and the next month in frequency
*/
private function getNextMonthInterval($currentMonth, $frequency)
private function getNextMonthInterval($currentMonth, $months)
{
$months = \laabs\explode(',', $frequency);
$numericMonths = [];
foreach ($months as $month) {
Loading