ParseCrontab 支持到秒级别的cron

简介: ParseCrontab 支持到秒级别的cron
<?php

namespace Job\Server;

class ParseCrontab
{
    static public $error;

    /**
     *  Parsing the timing format of crontab, Linux only supports to minutes /, and this class supports to seconds
     * @param string $crontab_string :
     *
     *      0     1    2    3    4    5
     *      *     *    *    *    *    *
     *      -     -    -    -    -    -
     *      |     |    |    |    |    |
     *      |     |    |    |    |    +----- day of week (0 - 6) (Sunday=0)
     *      |     |    |    |    +----- month (1 - 12)
     *      |     |    |    +------- day of month (1 - 31)
     *      |     |    +--------- hour (0 - 23)
     *      |     +----------- min (0 - 59)
     *      +------------- sec (0-59)
     * @param int $start_time timestamp [default=current timestamp]
     * @return int unix timestamp - 下一分钟内执行是否需要执行任务,如果需要,则把需要在那几秒执行返回
     * @throws InvalidArgumentException 错误信息
     */
    static public function parse($crontab_string, $start_time = null)
    {
        if (!preg_match('/^((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)$/i',
                        trim($crontab_string))
        ) {
            if (!preg_match('/^((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)\s+((\*(\/[0-9]+)?)|[0-9\-\,\/]+)$/i',
                            trim($crontab_string))
            ) {
                self::$error = "Invalid cron string: " . $crontab_string;
                return false;
            }
        }
        if ($start_time && !is_numeric($start_time)) {
            self::$error = "\$start_time must be a valid unix timestamp ($start_time given)";
            return false;
        }
        $cron  = preg_split("/[\s]+/i", trim($crontab_string));
        $start = empty($start_time) ? time() : $start_time;

        if (count($cron) == 6) {
            $date = array(
                'second'  => (empty($cron[0])) ? array(1 => 1) : self::_parse_cron_number($cron[0], 1, 59),
                'minutes' => self::_parse_cron_number($cron[1], 0, 59),
                'hours'   => self::_parse_cron_number($cron[2], 0, 23),
                'day'     => self::_parse_cron_number($cron[3], 1, 31),
                'month'   => self::_parse_cron_number($cron[4], 1, 12),
                'week'    => self::_parse_cron_number($cron[5], 0, 6),
            );
        } elseif (count($cron) == 5) {
            $date = array(
                'second'  => array(1 => 1),
                'minutes' => self::_parse_cron_number($cron[0], 0, 59),
                'hours'   => self::_parse_cron_number($cron[1], 0, 23),
                'day'     => self::_parse_cron_number($cron[2], 1, 31),
                'month'   => self::_parse_cron_number($cron[3], 1, 12),
                'week'    => self::_parse_cron_number($cron[4], 0, 6),
            );
        }
        if (
            in_array(intval(date('i', $start)), $date['minutes']) &&
            in_array(intval(date('G', $start)), $date['hours']) &&
            in_array(intval(date('j', $start)), $date['day']) &&
            in_array(intval(date('w', $start)), $date['week']) &&
            in_array(intval(date('n', $start)), $date['month'])

        ) {
            return $date['second'];
        }
        return null;
    }

    /**
     * 解析单个配置的含义
     * @param $s
     * @param $min
     * @param $max
     * @return array
     */
    static protected function _parse_cron_number($s, $min, $max)
    {
        $result = array();
        $v1     = explode(",", $s);
        foreach ($v1 as $v2) {
            $v3   = explode("/", $v2);
            $step = empty($v3[1]) ? 1 : $v3[1];
            $v4   = explode("-", $v3[0]);
            $_min = count($v4) == 2 ? $v4[0] : ($v3[0] == "*" ? $min : $v3[0]);
            $_max = count($v4) == 2 ? $v4[1] : ($v3[0] == "*" ? $max : $v3[0]);
            for ($i = $_min; $i <= $_max; $i += $step) {
                if (intval($i) < $min) {
                    $result[$min] = $min;
                } elseif (intval($i) > $max) {
                    $result[$max] = $max;
                } else {
                    $result[$i] = intval($i);
                }
            }
        }
        ksort($result);
        return $result;
    }
}
目录
相关文章
|
监控 数据可视化 PHP
Laravel Crontab 支持的最小单位是分钟,怎么实现秒级执行的需求呢?
Laravel Crontab 支持的最小单位是分钟,怎么实现秒级执行的需求呢?
469 0
Laravel Crontab 支持的最小单位是分钟,怎么实现秒级执行的需求呢?
|
26天前
|
监控 前端开发 安全
系统日志使用问题之DEBUG级别的日志主要用于什么阶段
系统日志使用问题之DEBUG级别的日志主要用于什么阶段
|
3月前
|
JSON Java 数据格式
动态修改JAVA日志输出级别
动态修改JAVA日志输出级别
|
存储 应用服务中间件 Shell
shell+定时任务+nginx信号管理实现日志按日期切割存储
shell+定时任务+nginx信号管理实现日志按日期切割存储
|
Arthas SQL 监控
动态修改LOGGER日志级别
大多数情况下,我们会在打印日志时定义日志的LOGGER级别,用来控制输出的信息范围。 一方面,过多的输出会影响查看日志的效率,另一方面,过少的日志让问题定位变得困难。 但当线上出现问题时,线上容器通常定义在info级别,发生一些疑难问题时,光靠info级别的日志很难定位问题。 一个典型的场景:在一些需要打印MySQL语句的场景,如果你正在使用MyBatis框架,由于MyBaits中SQL语句是DEBUG级别的信息,通常在线上容器就没法看到。
624 1