【问题标题】:Creating a "Next Run Time" date from a cronjob-like syntax从类似 cronjob 的语法创建“下一次运行时间”日期
【发布时间】:2015-07-16 14:52:41
【问题描述】:

在我正在创建的应用程序中,用户可以安排重复任务。简单地说,用于生成间隔模式的值是:

Minute: [0-59, 90 (each minute)]
Hour: [0-23, 90 (each hour)]
Day of month: [1-31, 90 (each day of month), 91 (last day of month)]
Month: [1-12, 90 (each month)]

因此,例如,我得到了这种格式:10 - 2 - 90 - 90 转换为 2015-07-16 2:10。确定下一个运行时间日期的方法能够向我显示这个日期。但是,我正在寻找一种有效的方法来检查下一个运行时间日期是否已经过去(简单的部分),然后再次生成第一个下一个运行时间日期。在这种情况下,它将是2015-07-17 2:10

我发现我们的大脑很容易完成这项任务,但我不确定应遵循哪些逻辑步骤以最有效的方式确定这一点(没有写出所有可能性)。

有什么建议吗?

【问题讨论】:

标签: php


【解决方案1】:

它工作正常。我正在使用PHP Cron Parser。它拥有我们需要的一切。

否则,您可以更轻松、更高效地使用Cron Expression。 Stack Overflow 中的一些参考答案 are already herehere

对于Cron Expression,您可以使用:

$cron = Cron\CronExpression::factory('@daily');
$cron->isDue();
echo $cron->getNextRunDate()->format('Y-m-d H:i:s');//this give next run date.
//echo $cron->getPreviousRunDate()->format('Y-m-d H:i:s');//this give previous run date.

而这与你所拥有的和 Cron Expression 所拥有的完全一样,

您只需使用PHP Cron Expression。希望这会有所帮助。

【讨论】:

  • 感谢您的回答,但也许我的问题不清楚?鉴于问题中的结构,我正在寻找(以编程方式)解决此问题的方法。
  • 对于 cron 表达式,你可以像这样使用 $cron->getNextRunDate()->format('Y-m-d H:i:s'); $cron->getPreviousRunDate()->format('Y-m-d H:i:s');在此链接的用法下提到了它,github.com/mtdowling/cron-expression
【解决方案2】:

这几乎是 Cron 语法,那么为什么要创建自己的东西来完成完全相同的工作呢?

切换到有效的 cron 语法并使用简单的库进行解析等应该很容易。

一个例子是https://github.com/mtdowling/cron-expression,您可以免费获得下一次运行日期:

$cron->getNextRunDate()->format('Y-m-d H:i:s');

您还可以使用 0/15 等值每 15 分钟运行一次,等等。 另一个好处是,cron 语法是常识,可以防止对格式的误解。

【讨论】:

  • 这看起来很有用。唯一的缺点是我必须重写一些部分,但我认为这并不麻烦。我先看看确定下一次运行日期的函数,看看能不能想出类似的东西。
  • 虽然这并不是我最初想要的,但你是第一个提出这个库的人。感谢您帮助我。
【解决方案3】:

我假设这是每天的间隔。如果不是,您可以调整strtotime 行。

您需要将日期转换为时间戳,然后在其上添加一天。 PHP 让这一切变得非常简单。

假设您已经将日期解析为国际格式2015-07-17 2:10,您可以执行以下操作:

$date = '2015-07-17 2:10'; // Parsed date
$timestamp = strtotime($date);
if($timestamp > time()){
    // Date hasn't hit yet
} else {
    $next_run = strtotime("+1 day", $timestamp);
}

【讨论】:

  • 在这种情况下你是对的,但诀窍在于增加时间。有些病例下个月 1 天 10 分钟。必须以某种方式确定。
  • 啊,我明白了,所以问题不是计算下一次运行的时间,问题是计算间隔是多少?在那种情况下,我的回答没有多大帮助
  • 没问题,感谢您的帮助!我需要“下一次运行时间”日期,以便将其列在状态列表中。
【解决方案4】:

查看https://github.com/fightbulc/moment.php,它提供了加/减秒、分钟、小时、月和年的可能性。 例如(取自 github 演示站点):

$m = new \Moment\Moment('2012-05-15T12:30:00', 'CET');
echo $m->addHours(2)->format(); // 2012-05-15T14:30:00+0200

$m = new \Moment\Moment('2012-05-15T12:30:00', 'CET');
echo $m->subtractDays(7)->subtractMinutes(15)->format(); //  2012-05-08T12:15:00+0200

【讨论】:

  • 我会看看这个,看看它是否有用。谢谢!
  • 问题不在于添加特定时间量的功能,而是根据给定的间隔模式确定下一次运行时间。然而,这是一个不错的库,但不是我想要解决的问题。
【解决方案5】:

为什么要担心它是否已经运行,或者它的下一次运行时间是什么时候?

您能每分钟运行一个脚本,检查所有匹配的作业,然后执行它们吗?

编写一个匹配特定时间点所有可能性的 SQL 查询应该不是一个大问题 :)

【讨论】:

  • 下一次运行时间用于显示在状态列表中。该脚本每分钟运行一次;)
  • 你需要把它存储在后端,还是只给出 cronjobs 的列表,让 javascript 计算并显示给用户?
  • 我不需要存储它,而是即时计算它。脚本每分钟运行一次,我可以检查“下一次运行日期”是否已经过去,但是我需要下一个“下一次运行日期”才能显示在屏幕上(这是一个状态板,用户可以在其中看到任务何时执行再次执行)
  • 嗯,这很容易更新视图 javasript,我还要添加一个日志表,在其中记录所有进程在启动时记录,以及完成需要多长时间,然后您可以检查您的工作已经通过简单的 ajax 调用启动了 jet,运行了多长时间等
  • 没错,但本质上这不是我所追求的。我仍然面临这个问题的原因。当今天的运行时间日期已经过去时,如何使用给定变量(当然因作业而异)日期有效且高效地确定下一次运行时间。
【解决方案6】:

您可以简单地使用原生的DateTime 类。

$timeString = '2015-07-16 2:10';
$date = DateTime::createFromFormat('Y-m-d H:i', $timeString);
$date->modify('+1 day');

$now = new DateTime();

if ($date > $now) {
    // The date is in the future
} else {
    // The date is today, or is in the past
}

但如果你需要真正的 cron 语法,@echox 的回答会好得多。

【讨论】:

  • 我知道这些可能性,但这不是我想要的。如果今天的 cron 作业任务已经通过,我正在寻找确定下一个运行时的方法。在某些情况下,可能是第二天,其他情况下是下一分钟,或下一小时,或下个月的最后一天,依此类推。这个答案没有帮助我,但也许它会在未来帮助其他人。
【解决方案7】:

说实话,我对接受和奖励的答案不太满意,因为我想自己弄清楚,而不是最终使用外部库并重写我的代码。

鉴于问题中描述的类似 cron 的语法,我创建了一个函数来确定下一次运行时间。如果您遇到类似的问题,我想分享它以帮助其他人。也许它会为您指明所需的方向。

一些演示案例

$cases = [
    // Every minute
    ['i' => 90, 'H' => 90, 'd' => 90, 'm' => 90],
    // Every 5th minute
    ['i' => 5, 'H' => 90, 'd' => 90, 'm' => 90],
    // Every day at 02:15
    ['i' => 15, 'H' => 2, 'd' => 90, 'm' => 90],
    // Every last day of the month at 15:20
    ['i' => 20, 'H' => 15, 'd' => 91, 'm' => 90],
    // June 4th at 12:37
    ['i' => 37, 'H' => 12, 'd' => 4, 'm' => 6],
    // Every minute between 04:00 and 05:00 at every day in October
    ['i' => 90, 'H' => 4, 'd' => 90, 'm' => 10],
];

功能:

function getNextRunTime($config) {
    $minute = $config['i'];
    $hour   = $config['H'];
    $day    = $config['d'];
    $month  = $config['m'];

    // Get minute
    switch($minute) {
        case 90 :
            $nextMinute = date('i', strtotime('now + 1 minute'));
            break;
        default :
            $nextMinute = $minute;
    }

    // Get hour
    switch($hour) {
        case 90 :
            if($minute == 90 || $nextMinute > date('i')) {
                $nextHour = date('H');
            } else {
                $nextHour = date('H', strtotime('now + 1 hour'));
            }
            break;
        default :
            $nextHour = $hour;
    }

    // Get day
    switch($day) {
        case 90 :
            if($hour == 90 && $nextHour > date('H')) {
                $nextDay = date('d');
            } elseif($hour <> 90 && $nextHour <= date('H')) {
                $nextDay = date('d', strtotime('now + 1 day'));
            } else {
                if($nextHour > date('H')) {
                    $nextDay = date('d');
                } else {
                    if ($nextMinute > date('i')) {
                        $nextDay = date('d');
                    } else {
                        $nextDay = date('d', strtotime('now + 1 day'));
                    }
                }
            }
            break;
        case 91 :
            if(date('t') == date('d')) {
                if($nextHour > date('H')) {
                    $nextDay = date('d');
                } elseif($nextHour == date('H') && $nextMinute > date('i')) {
                    $nextDay = date('d');
                } else {
                    $nextDay = date('t', strtotime('now + 1 month'));
                }
            } else {
                $nextDay = date('t');
            }
            break;
        default :
            $nextDay = $day;
    }

    // Get month
    switch($month) {
        case 90 :
            if($day == 90 || $nextDay > date('d')) {
                $nextMonth = date('m');
            } elseif($nextDay == date('d')) {
                if($hour == 90 || $nextHour > date('H')) {
                    $nextMonth = date('m');
                } elseif($nextHour == date('H')) {
                    if($minute == 90 || $nextMinute > date('i')) {
                        $nextMonth = date('m');
                    } else {
                        $nextMonth = date('m', strtotime('now + 1 month'));
                    }
                } else {
                    $nextMonth = date('m', strtotime('now + 1 month'));
                }
            } else {
                $nextMonth = date('m', strtotime('now + 1 month'));
            }
            break;
        default :
            $nextMonth = $month;
    }

    // Get year
    if($month == 90 || $nextMonth > date('m')) {
        $nextYear = date('Y');
    } elseif($nextMonth == date('m')) {
        if($day == 90 || $nextDay > date('d')) {
            $nextYear = date('Y');
        } elseif($nextDay == date('m')) {
            if($hour == 90 || $nextHour > date('H')) {
                $nextYear = date('Y');
            } elseif($nextHour == date('H')) {
                if($minute == 90 || $nextMinute > date('i')) {
                    $nextYear = date('Y');
                } else {
                    $nextYear = date('Y') + 1;
                }
            } else {
                $nextYear = date('Y') + 1;
            }
        } else {
            $nextYear = date('Y') + 1;
        }
    } else {
        $nextYear = date('Y') + 1;
    }

    // Create the timestamp for the 'Next Run Time'
    $nextRunTime = mktime($nextHour, $nextMinute, 0, $nextMonth, $nextDay, $nextYear);

    // Check if the job has to run every minute, maybe a reset to d-m-Y h:00 is possible
    if($nextRunTime > time() && $minute == 90) {
        $tempNextRunTime = mktime($nextHour, 0, 0, $nextMonth, $nextDay, $nextYear);

        if($tempNextRunTime > time()) {
            $nextMinute  = 0;
            $nextRunTime = $tempNextRunTime;
        }
    }

    // Check if the job has to run every hour, maybe a reset to d-m-Y 00:i is possible
    if($nextRunTime > time() && $hour == 90) {
        $tempNextRunTime = mktime(0, $nextMinute, 0, $nextMonth, $nextDay, $nextYear);

        if($tempNextRunTime > time()) {
            $nextHour    = 0;
            $nextRunTime = $tempNextRunTime;
        }
    }

    // Check if the job has to run every day, maybe a reset to 1-m-Y H:i is possible
    if($nextRunTime > time() && $day == 90) {
        $tempNextRunTime = mktime($nextHour, $nextMinute, 0, $nextMonth, 1, $nextYear);

        if($tempNextRunTime > time()) {
            $nextRunTime = $tempNextRunTime;
        }
    }

    // Return the Next Run Time timestamp
    return $nextRunTime;
}

输出(执行时间 23-09-2015, 11:12):

string '23-09-2015, 11:13' (length=17)
string '23-09-2015, 12:05' (length=17)
string '24-09-2015, 02:15' (length=17)
string '30-09-2015, 15:20' (length=17)
string '04-06-2016, 12:37' (length=17)
string '01-10-2015, 04:00' (length=17)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    • 2015-09-30
    • 1970-01-01
    相关资源
    最近更新 更多