Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP - Get date of next crontab's run

Tags:

php

cron

I want to get the next date to run the cron from a given string like Cron Format with seconds parameter (not fully equal as cron format).

My code:

$cron_format = explode(" ", "00 00 00 01 * *"); // <second> <minute> <hour> <day> <month> <week_day>
$date_diff   = explode(" ", "s i H d m w");     // php Date @link http://php.net/manual/en/function.date.php
$format = [];

foreach( $date_diff as $key=>$value) {
    $format[$value] = $cron_format[$key] !== "*" ? date($value, strtotime($cron_format[$key])) : date($value);
}

$spf = sprintf(
"%s-%s-%s %s:%s:%s", 
date("Y"), $format["m"], $format["d"], $format["H"], $format["i"], $format["s"]
);

$date = DateTime::createFromFormat("Y-m-d H:i:s", $spf);

// returns 2018-03-01 00:00:00, expected was 2018-04-01 00:00:00
echo $date->format("Y-m-d H:i:s"); 

Fiddle

It reads 2018-03-01 00:00:00 as expected, but what I am looking for is a way to get next Crontab run date (2018-04-01 00:00:00).

Setting a way to add a month does not solve the problem, since the cron format could be set hourly, as:

<second> <minute> <hour> <day> <month> <week_day>
   00       00      *      *      *         *
like image 615
fiskolin Avatar asked Mar 26 '18 13:03

fiskolin


2 Answers

No need to write more code for that. Please use below library to do that

https://github.com/mtdowling/cron-expression

Usage:

<?php
// Works with cron expression
$cron = new Cron\CronExpression::factory('15 2,6-12 */15 1 *');
$cron->getNextRunDate();
like image 69
Kamlesh Solanki Avatar answered Oct 30 '22 02:10

Kamlesh Solanki


I played a little bit around and here is my result as a function. Basically I split the elements, check the values for Wildcards. If found it will ignore all other Wildcards and set the value for the element with the first Wildcard +1. Further I check the d and m for zero-values, and if found they are replaced by the value 1. In the end i check, if the date with the current year would be smaller than the current date. if yes, it will use the current year, if no it will use the next year.

 function calculate_next_cronjob($cronjob, $elementpositions){

  $wildcard = false;
  $elements = preg_split('/[^\d*]+/', $cronjob);

  foreach(preg_split('/[^a-z]+/i', $elementpositions) as $key => $element){

    $value[$element] = $elements[$key];

    switch($element){
     case 's':
      if($value[$element] == '*'){
       $value[$element] = date('s') + 1;
       $wildcard = true;
      }
     break;
     case 'i':
      if($value[$element] == '*'){
       $value[$element] = date('i') + ($wildcard === true ? 0 : 1);
       $wildcard = true;
      }
     break;
     case 'H': 
      if($value[$element] == '*'){
       $value[$element] = date('H') + ($wildcard === true ? 0 : 1);
       $wildcard = true;
      }
     break;
     case 'd': 
      if($value[$element] == '*'){
       $value[$element] = date('d') + ($wildcard === true ? 0 : 1);
       $wildcard = true;
      }
      if(intval($value[$element]) == 0){
       $value[$element] = 1;          
      }
     break;
     case 'm': 
      if($value[$element] == '*'){
       $value[$element] = date('m') + ($wildcard === true ? 0 : 1);
       $wildcard = true;
      }
      if(intval($value[$element]) == 0){
       $value[$element] = 1; 
      }
     break;
      default:
      unset($value[$element]);
    }

  }

  $cy = date('Y');
  $ny = $cy + 1;

  if(time() < mktime($value['H'], $value['i'], $value['s'], $value['m'], $value['d'], $cy)){
   $value['Y'] = $cy;
  }else{
   $value['Y'] = $ny; 
  }

  return date('Y-m-d H:i:s', mktime($value['H'], $value['i'], $value['s'], $value['m'], $value['d'], $value['Y']));

 }  

Testrun:

 $cronjobs   = array();
 $cronjobs[] = array('00 00 00 00 *  00', 's  i  H  d m N');
 $cronjobs[] = array('00 00 00 *  *  00', 's  i  H  d m N');
 $cronjobs[] = array('00 00 *  *  *  00', 's  i  H  d m N');
 $cronjobs[] = array('00 *  *  *  *  00', 's  i  H  d m N');
 $cronjobs[] = array('*  *  *  *  *  00', 's  i  H  d m N');

 echo '<table>';
 foreach($cronjobs as $data){
  echo '<tr><td>';
  echo $data[0];
  echo '</td><td>';
  echo $data[1];
  echo '</td><td>';
  echo calculate_next_cronjob($data[0], $data[1]);
  echo '</td></tr>';
 }
 echo '</table>';

Output:

00 00 00 00 * 00 s i H d m N 2018-05-01 00:00:00 
00 00 00 *  * 00 s i H d m N 2018-04-17 00:00:00 
00 00 *  *  * 00 s i H d m N 2018-04-16 09:00:00 
00 *  *  *  * 00 s i H d m N 2018-04-16 08:25:00 
*  *  *  *  * 00 s i H d m N 2018-04-16 08:24:59 
like image 20
Bernhard Avatar answered Oct 30 '22 02:10

Bernhard