PHP类Crond时间规则算法

56 篇文章 0 订阅
4 篇文章 0 订阅
<?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] == '' 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值