×

php解析crontab时间格式

admin admin 发表于2020-07-15 17:40:31 浏览1681 评论0

抢沙发发表评论

crontab 时间格式:


配置说明

“* * * * * *”分 时 日 月 周

“0 3 * * * *”数字精确配置, 星号为任意.(每天凌晨3点整)

“15,30 3 * * *”逗号表示枚举 (每天3点15分和3点30分)

“15-30 3 * * *”短线表示范围 (每天的3点15分到30分)

“*/10 3 * * *”斜杠表示间隔 (每天3点0分到30分之间, 每10分钟一次)

“0-10,50-59/2 3 * * *”优先级:枚举>范围>间隔 (每天3点0分到10分以及50到59分期间, 每2分钟一次)

注意:不支持解析以英文名称配置的时间计划(如:”0 4 1 jan “)


应用场景: crontab配置一个php, 然后由php管理多个php的crontab任务

<?php
/**
* @file: Crontab.php
* @author: yuyunhe@zuoyebang.com
* @date: 2020/7/15 17:30
*/

//crontab 时间格式:
//
//配置   说明
//“* * * * * *”    分 时 日 月 周
//“0 3 * * * *”    数字精确配置, 星号为任意.(每天凌晨3点整)
//“15,30 3 * * *”  逗号表示枚举 (每天315分和330)
//“15-30 3 * * *”  短线表示范围 (每天的315分到30)
//“*/10 3 * * *”   斜杠表示间隔 (每天30分到30分之间, 10分钟一次)
//“0-10,50-59/2 3 * * *”   优先级:枚举>范围>间隔 (每天30分到10分以及5059分期间, 2分钟一次)
//注意:不支持解析以英文名称配置的时间计划(:”0 4 1 jan “)

/**
* crontab 时间格式php解析类(PHP 5 >= 5.1.0)
*
*/
class OpCloud_CronTab
{

   /**
    * 检查某时间($time)是否符合某个corntab时间计划($str_cron)
    *
    * @param int $time 时间戳
    * @param string $str_cron corntab的时间计划,如,"30 2 * * 1-5"
    *
    * @return bool/string 出错返回string(错误信息)
    */
   static public function check($time, $str_cron)
   {
       $format_time = self::format_timestamp($time);
       $format_cron = self::format_crontab($str_cron);
       if (!is_array($format_cron)) {
           return $format_cron;
       }
       return self::format_check($format_time, $format_cron);
   }

   /**
    * 使用格式化的数据检查某时间($format_time)是否符合某个corntab时间计划($format_cron)
    *
    * @param array $format_time self::format_timestamp()格式化时间戳得到
    * @param array $format_cron self::format_crontab()格式化的时间计划
    *
    * @return bool
    */
   static public function format_check(array $format_time, array $format_cron)
   {
       return (!$format_cron[0] || in_array($format_time[0], $format_cron[0]))
           && (!$format_cron[1] || in_array($format_time[1], $format_cron[1]))
           && (!$format_cron[2] || in_array($format_time[2], $format_cron[2]))
           && (!$format_cron[3] || in_array($format_time[3], $format_cron[3]))
           && (!$format_cron[4] || in_array($format_time[4], $format_cron[4]));
   }

   /**
    * 格式化时间戳,以便比较
    *
    * @param int $time 时间戳
    *
    * @return array
    */
   static public function format_timestamp($time)
   {
       return explode('-', date('i-G-j-n-w', $time));
   }

   /**
    * 格式化crontab时间设置字符串,用于比较
    *
    * @param string $str_cron crontab的时间计划字符串,如"15 3 * * *"
    *
    * @return array/string 正确返回数组,出错返回字符串(错误信息)
    */
   static public function format_crontab($str_cron)
   {
       //格式检查
       $str_cron = trim($str_cron);
       $reg      = '#^((\*(/\d+)?|((\d+(-\d+)?)(?3)?)(,(?4))*))( (?2)){4}$#';
       if (!preg_match($reg, $str_cron)) {
           return '格式错误';
       }

       try {
           //分别解析分、时、日、月、周
           $arr_cron    = [];
           $parts       = explode(' ', $str_cron);
           $arr_cron[0] = self::parse_cron_part($parts[0], 0, 59);//
           $arr_cron[1] = self::parse_cron_part($parts[1], 0, 59);//
           $arr_cron[2] = self::parse_cron_part($parts[2], 1, 31);//
           $arr_cron[3] = self::parse_cron_part($parts[3], 1, 12);//
           $arr_cron[4] = self::parse_cron_part($parts[4], 0, 6);//周(0周日)
       } catch (Exception $e) {
           return $e->getMessage();
       }

       return $arr_cron;
   }

   /**
    * 解析crontab时间计划里一个部分(分、时、日、月、周)的取值列表
    * @param string $part 时间计划里的一个部分,被空格分隔后的一个部分
    * @param int $f_min 此部分的最小取值
    * @param int $f_max 此部分的最大取值
    *
    * @return array 若为空数组则表示可任意取值
    * @throws Exception
    */
   static protected function parse_cron_part($part, $f_min, $f_max)
   {
       $list = [];

       //处理"," -- 列表
       if (false !== strpos($part, ',')) {
           $arr = explode(',', $part);
           foreach ($arr as $v) {
               $tmp  = self::parse_cron_part($v, $f_min, $f_max);
               $list = array_merge($list, $tmp);
           }
           return $list;
       }

       //处理"/" -- 间隔
       $tmp  = explode('/', $part);
       $part = $tmp[0];
       $step = isset($tmp[1]) ? $tmp[1] : 1;

       //处理"-" -- 范围
       if (false !== strpos($part, '-')) {
           [$min, $max] = explode('-', $part);
           if ($min > $max) {
               throw new Exception('使用"-"设置范围时,左不能大于右');
           }
       } elseif ('*' == $part) {
           $min = $f_min;
           $max = $f_max;
       } else {//数字
           $min = $max = $part;
       }

       //空数组表示可以任意值
       if ($min == $f_min && $max == $f_max && $step == 1) {
           return $list;
       }

       //越界判断
       if ($min < $f_min || $max > $f_max) {
           throw new Exception('数值越界。应该:分0-59,时0-59,日1-31,月1-12,周0-6');
       }

       return $max - $min > $step ? range($min, $max, $step) : [(int)$min];
   }
}


分享到:

群贤毕至

访客