1. 程式人生 > >PHP類Crond時間規則演算法

PHP類Crond時間規則演算法

<?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] == '*' || empty($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歡迎留言。