dragonmantank/cron-expression
Parse and evaluate PHP cron expressions with advanced features like ranges, intervals, weekdays (W), last days (L), and nth occurrences (#). Easily check if a cron job is due, calculate next/previous run dates, and skip multiple matches. Supports complex expressions like */12, 2-59/3, and @daily—ide...
Install via Composer:
composer require dragonmantank/cron-expression
Start by parsing a cron expression and checking if it’s due or calculating the next run time:
use Cron\CronExpression;
$cron = CronExpression::factory('@daily');
if ($cron->isDue()) {
// Execute job
}
echo $cron->getNextRunDate()->format('Y-m-d H:i:s');
Key entry points: CronExpression::factory() (deprecated but still functional), new CronExpression(...), isDue(), getNextRunDate(), and getPreviousRunDate().
isDue() in CLI tasks or background workers to determine job execution. Wrap in a loop with getNextRunDate($currentTime, $skip) to advance multiple runs.DateTimeInterface (e.g., new DateTime('now', new DateTimeZone('America/New_York'))) to getNextRunDate() for accurate DST handling.@workday) via CronExpression::setFieldFactory(new CustomFieldFactory()) or by extending field parsing (v3.3+ supports custom alias registration).CronExpression::isValidExpression() to validate user inputs before persisting schedules.CronExpression to assert timing logic—e.g., inject a fixed $currentTime for deterministic isDue() checks.0 0 1 * 1), it now uses OR, not AND. This is nonstandard in some cron implementations (e.g., anacron), so verify expectations.09 in minute/hour fields are parsed correctly, but avoid leading zeros elsewhere (e.g., 01 in month is fine; 009 may cause issues—use 9).L, W, #, and ? quirks:
LW works only on Day-of-Month, not Day-of-Week.? must only appear in one of DOM/DOW (not both).L in Day-of-Week (e.g., 5L) gives the last Friday, not the last weekday of the month.isDue() uses server time unless you pass a DateTimeInterface with explicit timezone. DST transitions may cause off-by-an-hour behavior—test during transitions.getNextRunDate(null, 10000) for large skips—specify $currentTime and reasonable $skip to avoid infinite loops or excessive computation.CronExpression::factory() in new code; use the constructor. Methods like determineTimezone() are @internal.^3.3.getParts() to inspect parsed fields. For complex expressions, validate with tools like crontab.guru before testing in PHP.How can I help you explore Laravel packages today?