CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due

Last update: Aug 14, 2022

PHP Cron Expression Parser

Latest Stable Version Total Downloads Build Status StyleCI

The PHP cron expression parser can parse a CRON expression, determine if it is due to run, calculate the next run date of the expression, and calculate the previous run date of the expression. You can calculate dates far into the future or past by skipping n number of matching dates.

The parser can handle increments of ranges (e.g. */12, 2-59/3), intervals (e.g. 0-9), lists (e.g. 1,2,3), W to find the nearest weekday for a given day of the month, L to find the last day of the month, L to find the last given weekday of a month, and hash (#) to find the nth weekday of a given month.

More information about this fork can be found in the blog post here. tl;dr - v2.0.0 is a major breaking change, and @dragonmantank can better take care of the project in a separate fork.

Installing

Add the dependency to your project:

composer require dragonmantank/cron-expression

Usage



require_once '/vendor/autoload.php';

// Works with predefined scheduling definitions
$cron = new Cron\CronExpression('@daily');
$cron->isDue();
echo $cron->getNextRunDate()->format('Y-m-d H:i:s');
echo $cron->getPreviousRunDate()->format('Y-m-d H:i:s');

// Works with complex expressions
$cron = new Cron\CronExpression('3-59/15 6-12 */15 1 2-5');
echo $cron->getNextRunDate()->format('Y-m-d H:i:s');

// Calculate a run date two iterations into the future
$cron = new Cron\CronExpression('@daily');
echo $cron->getNextRunDate(null, 2)->format('Y-m-d H:i:s');

// Calculate a run date relative to a specific time
$cron = new Cron\CronExpression('@monthly');
echo $cron->getNextRunDate('2010-01-12 00:00:00')->format('Y-m-d H:i:s');

CRON Expressions

A CRON expression is a string representing the schedule for a particular command to execute. The parts of a CRON schedule are as follows:

*    *    *    *    *
-    -    -    -    -
|    |    |    |    |
|    |    |    |    |
|    |    |    |    +----- day of week (0 - 7) (Sunday=0 or 7)
|    |    |    +---------- month (1 - 12)
|    |    +--------------- day of month (1 - 31)
|    +-------------------- hour (0 - 23)
+------------------------- min (0 - 59)

This library also supports a few macros:

  • @yearly, @annually - Run once a year, midnight, Jan. 1 - 0 0 1 1 *
  • @monthly - Run once a month, midnight, first of month - 0 0 1 * *
  • @weekly - Run once a week, midnight on Sun - 0 0 * * 0
  • @daily - Run once a day, midnight - 0 0 * * *
  • @hourly - Run once an hour, first minute - 0 * * * *

Requirements

  • PHP 7.1+
  • PHPUnit is required to run the unit tests
  • Composer is required to run the unit tests

Projects that Use cron-expression

GitHub

https://github.com/dragonmantank/cron-expression
Comments
  • 1. RuntimeException: Impossible CRON expression at Date 2022-10-30 on Europe/Berlin Timezone

    At Version Version 3.2.2 I got a RuntimeException when the Date reaches the German time change.

    The following Code works fine:

    $cronExpression = new CronExpression('0 0 1 * *');
    $date = new \DateTime('2022-10-30', new \DateTimeZone("UTC"));
    $cronExpression->getNextRunDate($date)
    

    but if I change the Timezone to Europe/Berlin:

    $cronExpression = new CronExpression('0 0 1 * *');
    $date = new \DateTime('2022-10-30', new \DateTimeZone("Europe/Berlin"));
    $cronExpression->getNextRunDate($date)
    

    I get a RuntimeException: Impossible CRON expression

    Debugging from AbstractField::timezoneSafeModify:

        protected function timezoneSafeModify(DateTimeInterface $dt, string $modification): DateTimeInterface
        {
            $timezone = $dt->getTimezone();
            var_dump($dt);
            $dt = $dt->setTimezone(new \DateTimeZone("UTC"));
            var_dump($dt);
            $dt = $dt->modify($modification);
            $dt = $dt->setTimezone($timezone);
            die(var_dump($dt));
            return $dt;
        }
    
    object(DateTime)[2430]
      public 'date' => string '2022-10-30 00:00:00.000000' (length=26)
      public 'timezone_type' => int 3
      public 'timezone' => string 'Europe/Berlin' (length=13)
    /src/Cron/AbstractField.php:327:
    object(DateTime)[2430]
      public 'date' => string '2022-10-29 22:00:00.000000' (length=26)
      public 'timezone_type' => int 3
      public 'timezone' => string 'UTC' (length=3)
    /src/Cron/AbstractField.php:330:
    object(DateTime)[2430]
      public 'date' => string '2022-10-30 23:00:00.000000' (length=26)
      public 'timezone_type' => int 3
      public 'timezone' => string 'Europe/Berlin' (length=13)
    

    If needed, i can pr a failing Test by tomorrow.

    Reviewed by Apfelfrisch at 2022-01-05 14:03
  • 2. Valid cron expression is not accepted

    Input

    $expression = '2,17,35,47 5-7,11-13 * * *';

    Expected behaviour

    • CronExpression::isValidExpression($expression) returns true
    • CronExpression::factory($expression) returns a CronExpression instance.

    Referring to crontab.guru this is a valid expression.

    Actual behaviour

    • CronExpression::isValidExpression($expression) returns false
    • CronExpression::factory($expression) throws an InvalidArgumentException with message Invalid CRON field value 5-7,11-13 at position 1

    Identified cause

    Range and list at the same time in the same field are not accepted.

    See https://github.com/dragonmantank/cron-expression/blob/v2.0.0/src/Cron/AbstractField.php#L210


    I would like to provide a PR, if you confirm this is a valid issue.

    I once implemented a cron expression validator myself, which allows this expression. I updated it today to be compatible with the PHPUnit 6+ version.

    Reviewed by hollodotme at 2017-12-05 16:20
  • 3. Bug: "0-59/59 10 * * *" skips 10:00

    @dragonmantank

    cron schedule: 0-59/59 10 * * *

    $times = [];
    $now = new Carbon();
    
    $cron = CronExpression::factory("0-59/59 10 * * *");
    for ($k = 0 ; $k < 20; $k++){
    	$times[] = $cron->getNextRunDate($now, $k);
    }
    

    There is a bug. 2020-08-20 10:00:00 is missed. The first time is 2020-08-20 10:59:00

    Reviewed by pjebs at 2020-08-20 05:20
  • 4. Add PHPCS fixer to project

    I think it is useful to have working PHPCS functionality in the project it self, which can now simply be executed using:

    composer phpcs for a dry run composer phpcs-fix for actual fixing.

    For now only applied @PSR2

    Reviewed by holtkamp at 2019-02-24 17:20
  • 5. Multiple "Day if Month" values including "L" for Last Day of Month

    I love this library. I'm using it to run billing on varying schedules.

    I just ran into a situation where one customer needs an invoice generated from the 1st of the month through the 15th of the month, and from the 15th of the month through the last day of the month. So invoice generation needs to run at the end of the day (for them this is 6:00 PM PST) on the 15 and the last day of the month. My schedule looks like this:

    0 18 L,15 * *

    Unfortunately, it does not look like the "day of the month" supports multiple comma-separated days including "L" for the last day, the way it does numeric days.

    If this is a desired feature, I'm happy to try and tackle it.

    Reviewed by iambrianreich at 2018-05-01 15:04
  • 6. range(): step exceeds the specified range

    @dragonmantank I'm using v2 of library:

    $now = new Carbon();
    $cron = CronExpression::factory("41-59/24 5 * * 5");
    for ($k = 0 ; $k < 20; $k++){
    	$t = $cron->getNextRunDate($now, $k);
    	$times[] = $t; // Store next 20 values
    }
    		
    

    Error:

    range(): step exceeds the specified range

    /vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php:148 /vendor/dragonmantank/cron-expression/src/Cron/AbstractField.php:53 /vendor/dragonmantank/cron-expression/src/Cron/MinutesField.php:31 /vendor/dragonmantank/cron-expression/src/Cron/CronExpression.php:362 /vendor/dragonmantank/cron-expression/src/Cron/CronExpression.php:199

    Reviewed by pjebs at 2020-08-19 03:56
  • 7. set phpstan to level max and fix issues

    Hello,

    I do:

    • Set PHPStan to level max (ie 8) https://phpstan.org/user-guide/rule-levels.
    • Fix issues throws by PHPStan
    • Add PHPStan to Travis

    It improve DX :rocket:

    Reviewed by oallain at 2020-10-05 22:19
  • 8. or/and bug

    I use the library in a script that monitors cronjobs. Now we have the issue that crond handle the expression in another way than the library predicted.

    The expression is: 30 0 1 * 1

    Crond run on every monday and on every 1th of the month. Crond use OR. The library use AND. So the library thinks cron would only run when the 1th of the month is a monday.

    Is it intentional that the library behaves like this or is it a bug?

    Reviewed by adminc at 2019-02-19 18:24
  • 9. Add PHP7.x primitive type hints to method declaration

    The library supports all PHP Versions >=7.0.0 according to the composer.json. That's why this PR adds strict scalar type hints to the methods that are currently defined in the src folder. I added the types according to the DocBlock of each function.

    Feedback is much appreciated :tada:

    Reviewed by legionth at 2019-01-15 21:28
  • 10. Change private variables to protected

    This allows extending classes to access the order for parts the same way as the base class.

    This introduces no breaking changes. Could be introduced as a patch release.

    Reviewed by DerekCresswell at 2020-12-02 18:56
  • 11. Human Readable cron String

    FEATURE request:

    It would be nice to have a method to translate cron string to a human readable format, like prettyCron js library (http://azza-bazoo.github.io/prettycron/). So for example:

    Cron expression: 0 * * * * Human readable: Every hour, on the hour

    Cron expression: 30 * * * 1 Human readable: Every 30th minute past every hour on Mon

    Cron expression: 15,45 9,21 * * * Human readable: 09:15, 09:45, 21:15 and 21:45 every day

    Cron expression: 18,19 7 5 * * Human readable: 07:18 and 07:19 on the 5th of every month

    Cron expression: * * 25 12 * Human readable: Every minute on the 25th in Dec

    Cron expression: 0 * 1,3 * * Human readable: Every hour, on the hour on the 1 and 3rd of every month

    Cron expression: 0 17 * 1,4,7,10 * Human readable: 17:00 every day in Jan, Apr, Jul and Oct

    Reviewed by paianoa at 2020-04-28 11:33
  • 12. [PHP 8.2] Fix `${var}` string interpolation deprecation

    Reviewed by Ayesh at 2022-06-19 10:49
  • 13. "0 0 1-7,14-21 * Wed" the getNextRunDate is failing.

    The purpose of this CRON expression is to run every 2 weeks with a specific day. ( on my example i have Wednesday )

    Today we are the 18 may 2022.

    cronExpressionWeekly = "0 0 1-7,14-21 * Wed"

    (new CronExpression($cronExpressionWeekly))->getNextRunDate('now')->format('d.m.Y')

    the result return 2022-05-19 00:00:00 which is a Thursday. the cron expression is not respected at all.

    I believe the issue is about the range. 1-7,14-21

    Reviewed by delphimat at 2022-05-18 07:25
Doctrine type mappings for brick/date-time
Doctrine type mappings for brick/date-time

brick/date-time-doctrine Doctrine type mappings for brick/date-time. Introduction This library provides type mappings to use brick/date-time objects s

Jun 20, 2022
Add jalali(persian) date to akaunting software

Akaunting Jalali Date Akaunting Jalali Date is a free module developed for Akaunting. It automatically converts all dates to jalali date and change gr

Dec 22, 2021
A package which provides a monthly calendar with days and events depending on given months and events.

A package which provides a monthly calendar with days and events depending on given months and events. This is where your description should go. Try a

Dec 4, 2021
Parse, validate, manipulate, and display dates in PHP w/ i18n support. Inspired by moment.js

Support I am a dad now for the last 1,5 years and that clearly shows in being on time with merging PRs or pushing this package further. Time is the bi

Aug 8, 2022
Parse and validate crontab expressions in PHP

Standard (V7) compliant crontab expression parser/validator with support for time zones; see "man 5 crontab" for possible expressions.

Dec 27, 2021
This library helps PHP users to convert and using Jalali DateTime format

Easy Jalali for PHP V1.0.0 Jalali calendar converter for Persian users in Iran, Afghanistan and other countries that use Jalali calendar. Very thanks

Mar 20, 2022
A simple PHP API extension for DateTime.

Carbon An international PHP extension for DateTime. http://carbon.nesbot.com <?php use Carbon\Carbon; printf("Right now is %s", Carbon::now()->toDat

Aug 10, 2022
The easy PHP Library for calculating holidays

Introduction Yasumi (Japanese for 'Holiday'「休み」) is the easy PHP library that helps you retrieve the dates and names of holidays and other special cel

Aug 8, 2022
The missing PHP 5.3+ calendar management library.

CalendR CalendR is an Object Oriented Calendar management library on top of PHP5.3+ Date objects. You can use it to deal with all your needs about cal

Jul 31, 2022
iCal-creator for PHP - This package offers an abstraction layer for creating iCalendars files

This package offers an abstraction layer for creating iCalendars files. By using this PHP package, you can create *.ics files without the knowledge of the underling format. The output itself will follow RFC 5545 as good as possible.

Aug 12, 2022
CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due

The PHP cron expression parser can parse a CRON expression, determine if it is due to run, calculate the next run date of the expression, and calculate the previous run date of the expression. You can calculate dates far into the future or past by skipping n number of matching dates.

Aug 14, 2022
Smd horizon - Next/previous Textpattern article without restrictions

smd_horizon The existing tags <txp:next_title />, <txp:link_to_next /> and their prev counterparts cease to function when they reach the first/last po

Oct 22, 2019
Cron expression generator built on php8
Cron expression generator built on php8

The most powerful and extendable tool for Cron expression generation Cron expression generator is a beautiful tool for PHP applications. Of course, th

Aug 5, 2022
Date/Time Picker widget for Yii2 framework Based on Eonasdan's Bootstrap 3 Date/Time Picker
Date/Time Picker widget for Yii2 framework Based on Eonasdan's Bootstrap 3 Date/Time Picker

Yii2 Date/Time Picker Widget Date/Time Picker widget for Yii2 framework Based on Eonasdan's Bootstrap 3 Date/Time Picker Demo Since this is a part of

Mar 14, 2022
A cosmetics plugin that is highly incomplete & unoptimized (as it was roughly coded in a small period of time due to IRL issues), that I got scammed for,

CosmeticsPlus A cosmetics plugin that is highly incomplete and; unoptimized (as it was roughly coded in a small period of time due to IRL issues), tha

Feb 7, 2022
Analyze content to determine the appropriate Internet media type

Canal Content analysis for the purpose of determining Internet media types. Requirements PHP 5.3+ Installation Through Composer as dflydev/canal. Usag

Feb 11, 2022
Determine the geographical location of website visitors based on their IP addresses.

GeoIP for Laravel Determine the geographical location and currency of website visitors based on their IP addresses. GeoIP for Laravel on Packagist Geo

Aug 15, 2022
Determine the geographical location of website visitors based on their IP addresses.

Determine the geographical location and currency of website visitors based on their IP addresses.

Aug 4, 2022
PHP Expression Language

PHP Expression Language The purpose of this library is to provide a common base for an PHP Expression Language. This is not really a creative library

Sep 21, 2021
Arithmetic expression solver PHP library

arithmexp An arithmetic expression solver Usage $operators = OperatorRegistry::default(); $expression = new ArithmeticExpression($operators, "4 - 3 +

Jun 29, 2022