PHP - 获取下一个crontab运行的日期

时间:2018-03-26 13:51:35

标签: php cron

我希望Cron Format的给定字符串中获取下一个运行cron 的日期seconds参数(不完全等于cron格式)。

我的代码:

$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

它按预期显示2018-03-01 00:00:00,但我要找的是获得下一个Crontab运行日期(2018-04-01 00:00:00)的方法。

设置添加月份的方法无法解决问题,因为 cron格式可以按小时设置,如下:

<second> <minute> <hour> <day> <month> <week_day>
   00       00      *      *      *         *

2 个答案:

答案 0 :(得分:13)

无需为此编写更多代码。请使用下面的库来做到这一点

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

用法:

<?php
// Works with cron expression
$cron = new Cron\CronExpression::factory('15 2,6-12 */15 1 *');
$cron->getNextRunDate();

答案 1 :(得分:6)

我玩了一下,这是我的结果作为一个功能。基本上我拆分元素,检查通配符的值。如果找到它将忽略所有其他通配符并使用第一个通配符+1设置元素的值。此外,我检查d和m的零值,如果发现它们被值1替换。最后检查,如果当前年份的日期小于当前日期。如果是,它将使用当前年份,如果没有它将使用下一年。

 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>';

输出:

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