<?php
/**
* Created by PhpStorm.
* User: duyue
* Date: 2018/2/20
* Time: 23:10
* 此类仅用于判断给定的时间是否符合时间规则,如果符合则返回true其它业务逻辑自行处理
* 使用说明
* format = '* * * * * ';
* 本类模仿crond的规则分5个部分分别是分、时、日期、月、周(的第几天)
* 每部分可单独设置为一个数,如:1 * * * * ,当分为1时 true
* 可以使用 '/' 来分开设置重复规则,如: * / 1 * * * * , 每分钟 ; * / 2 * * * * 每两分钟(注意每部分之间是没有空格的,这里是PHP的注释部分)
* 可以设置区间: 4-20/2 * * * * , 当分为4 - 20之间,并且为2的倍数时
* 可以为集合: * /5,8,10 * * * * , 当分为5,8,10时返回true,其它部分同理。
* '0 23 * * 6' 每周六的11点
* '* 23-7/1 * * * ' 每天晚上23-7点,每隔一小时
*/
namespace app\extend;
class CrondTime{
public static function check($format,$check_time = 0)
{
$time = intval($check_time) > 0 ? $check_time : time();
$cNumber = [
date('i',$time), //分 0 - 59
date('H',$time), //时 0 - 23
date('j',$time), //日期, 1- 31
date('m',$time), //月 1 - 12
date('w',$time), //周 星期中的第几天 0(周日)至6(周六)
];
$cronArr = explode(' ',$format);
//逐个检查,非*全符合则返回true,否则返回false
for($i = 0; $i<5;$i++){
if($cronArr[$i] == '*' || $cronArr[$i] == '') continue;
if(self::checkNumber($cNumber[$i],$cronArr[$i]) === false){
return false;
}
}
return true;
}
/**
* 检查一个数字是否符合
* @param $number 要检查的数字
* @param $str 规则字符
* @return bool 符合返回true
*/
private function checkNumber($number,$str)
{
if(strpos($str,'/') === false && strpos($str,',') === false && strpos($str,'-') === false){
//单数
if($number == $str) return true;
return false;
}
//检查是否含有'/'
if(strpos($str,'/') === false){
//不含'/'
if(strpos($str,',') !== false){
//集合
if(in_array($number,explode(',',$str))) return true;
return false;
}
if(strpos($str,'-') !== false){
//区间
$areaArr = explode('-',$str);
$min = intval(trim($areaArr[0]));
$max = intval(trim($areaArr[1]));
if($number >= $min && $number <= $max) return true;
return false;
}
}else{
//有 '/' ,分左右两部分,左边检查集合、区间。右侧检查余数是否为0
$leftCheck = $rightCheck = false;
$tmp = explode('/',$str);
$leftStr = $tmp[0];
$rightStr = $tmp[1];
//如果左侧是*的话,右侧为数字则取模
$leftCheck = self::checkLevel3($number,$leftStr,true);
$rightCheck = self::checkLevel3($number,$rightStr,false);
if($leftCheck===true && $rightCheck === true) return true;
return false;
}
}
/**
* 检查3级字符
* @param $number
* @param $str
* @param bool $is_left
* @return bool
*/
private function checkLevel3($number,$str,$is_left = false){
if($str === '*') return true;
//三级中已经没有 '/' ,只需要检查是否是单数、集合、区间。
if(strpos($str,',') === false && strpos($str,'-') === false){
if($is_left === true){
if($number == $str) return true;
return false;
}else{
//echo $number;exit();
//右侧单数,进行取模运算
if($number%$str == 0) return true;
return false;
}
}
if(strpos($str,',') !== false){
//集合
if(in_array($number,explode(',',$str))) return true;
return false;
}
if(strpos($str,'-') !== false){
//区间
$areaArr = explode('-',$str);
$min = intval(trim($areaArr[0]));
$max = intval(trim($areaArr[1]));
if($number >= $min && $number <= $max) return true;
return false;
}
}
}
这里使用的命名空间,复制的时候稍注意一点。
防linux crond 时间规则算法,初步测试暂未发现什么问题。如果你发现的BUG欢迎留言。
-----------------------------
2023年8月10日更正bug 当某一项为0时,empty(0) == true 导致直接跳过,不去校验证
Line 37行,已修正 $conrArr[$i] == ''