dragonmantank/cron-expression - PHP cron parser guide
At 04:30, every day.
Next runs · UTC
- —
- —
- —
- —
- —
Calendar
September 2026 · UTC
0 runs
About this tool
dragonmantank/cron-expression is the de-facto cron parser for PHP - used by Laravel scheduling, Symfony Scheduler, and most modern PHP scheduling libraries. It supports the standard 5-field syntax plus the L, W, ? and # modifiers used by Quartz / AWS EventBridge dialects.Using cron-expression directly
<?php
require 'vendor/autoload.php';
use Cron\CronExpression;
$cron = new CronExpression('0 9 * * 1-5');
// Is the cron due right now?
if ($cron->isDue()) {
runJob();
}
// When does it fire next?
$next = $cron->getNextRunDate();
echo $next->format('Y-m-d H:i'); // e.g. "2026-04-27 09:00"
// Multi-step preview
foreach ($cron->getMultipleRunDates(5) as $date) {
echo $date->format('Y-m-d H:i') . "\n";
}Laravel scheduling on top of cron-expression
<?php
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('reports:daily')
->dailyAt('09:00')
->timezone('America/New_York');
$schedule->command('billing:close-month')
->lastDayOfMonth(); // → '0 0 L * *'
$schedule->command('cleanup:hourly')
->cron('15 * * * *'); // raw cron expression
}Laravel's named helpers compile to cron expressions under the hood. lastDayOfMonth() uses L, which the underlying parser supports.
Symfony Scheduler on top of cron-expression
<?php
use Symfony\Component\Scheduler\Attribute\AsSchedule;
use Symfony\Component\Scheduler\Schedule;
use Symfony\Component\Scheduler\ScheduleProviderInterface;
use Symfony\Component\Scheduler\Trigger\CronExpressionTrigger;
#[AsSchedule('default')]
final class DefaultSchedule implements ScheduleProviderInterface
{
public function getSchedule(): Schedule
{
return (new Schedule())
->add(
CronExpressionTrigger::fromSpec('0 9 * * 1-5')
->message(new MorningDigestMessage()),
CronExpressionTrigger::fromSpec('0 0 L * *')
->message(new MonthEndMessage()),
);
}
}Modifier support
L- last day of month or last weekday-of-month.LW- last weekday of the month.W- nearest weekday to the given day-of-month.?- no specific value (compatibility token).#- Nth weekday of month, e.g.2#1= first Monday.
Pitfalls
- Default timezone - `getNextRunDate()` uses the PHP default timezone. Set it via
date_default_timezone_setor pass an explicitDateTimeZone. - Laravel scheduler precision - runs every minute via a single OS cron, so jobs fire somewhere in their target minute (not at the exact second).
- Backward-compat with v1 - older versions used
CronExpression::factory(). New code usesnew CronExpression(...).
Examples
- 0 18 * * *Every day at 18:00
- 0 */5 * * *Every 5 hours
- 0 18 * * 1-5Weekdays at 18:00
- 0 0 1 * *Once a month, on the 1st at midnight
Cheatsheet
Full cheatsheet| Field | Req. | Range | Wildcards |
|---|---|---|---|
| minute | yes | 0-59 | , - * / |
| hour | yes | 0-23 | , - * / |
| day of month | yes | 1-31 | , - * / |
| month | yes | 1-12 or JAN-DEC | , - * / |
| day of week | yes | 0-6 or names; some dialects use 0-7 or 1-7 — see Dialects | , - * / |
Frequently asked questions
Syntax
How many fields does dragonmantank/cron-expression use?
It uses the standard five-field order: minute, hour, day of month, month, and day of week. It does not add a leading seconds field.
Which extended cron operators does dragonmantank support?
dragonmantank/cron-expression supports L, W, #, and ? in their compatible day-field positions, in addition to lists, ranges, wildcards, and steps.
Does dragonmantank support @daily and other aliases?
Yes. The parser supports @yearly, @annually, @monthly, @weekly, @daily, @midnight, and @hourly aliases.
Timing
What's the difference between isDue() and getNextRunDate()?
isDue() checks whether the cron should fire right now (matches the current minute). getNextRunDate() returns the next time the cron will fire. Use isDue() inside a per-minute scheduler loop; use getNextRunDate() when computing future schedules.
Days and months
How are day-of-month and day-of-week combined by dragonmantank?
dragonmantank follows Vixie cron's OR semantics when both day fields are restricted. A date is due when either restricted day field matches.
How do I express the last day of a month in dragonmantank?
Use 0 0 L * * for midnight on the last calendar day. The L value automatically accounts for 28-, 29-, 30-, and 31-day months.
How do I express an nth weekday with dragonmantank?
Use # in the day-of-week field, such as 1#1 for the first Monday under the library's weekday numbering. Preview dates before deploying numeric weekday expressions.
Timezones and DST
Which timezone does dragonmantank use?
Date calculations use the timezone supplied to the method or PHP's configured default. Pass an explicit timezone when application and server defaults may differ.
Can DST change dragonmantank's next run date?
Yes. Calendar schedules are resolved in a timezone, so missing and repeated local times can affect the resulting occurrence. Use UTC when wall-clock behavior is unnecessary.
Platforms
What PHP versions does dragonmantank/cron-expression support?
Current dragonmantank/cron-expression 3.x requires PHP 8.2 or newer. Check the package's version constraints before selecting an older release for an older PHP runtime.
Is this what Laravel uses for its scheduler?
Yes. Laravel's task scheduler is built on top of dragonmantank/cron-expression. The named helpers (->daily(), ->weekdays(), ->lastDayOfMonth()) compile down to cron strings the parser handles.
Does Symfony Scheduler also use this?
Symfony Scheduler 6.3+ uses cron-expression internally. The CronExpressionTrigger class wraps a cron string and resolves the next run time using dragonmantank's parser.
Debugging
How can I preview several dragonmantank run dates?
Call getMultipleRunDates(count) on a CronExpression. Reviewing several dates is especially useful for month-end, weekday, and DST-sensitive schedules.
How often must Laravel evaluate dragonmantank schedules?
Laravel normally runs schedule:run every minute so isDue() can dispatch matching entries. A missing or delayed outer scheduler prevents due tasks from starting.
Crontap
Can Crontap run a dragonmantank cron schedule?
Yes. You can run a compatible HTTP endpoint on Crontap; confirm dialect-specific operators before copying an expression from the PHP parser.
Write the cron here. Run it on Crontap.
Point Crontap at any URL. Pick any cron. Done.
WordPress, Shopify, Railway, Cloud Run, Vercel, HubSpot, Ghost, your own box. If it answers HTTP, Crontap can drive it on a clock you can read, in the timezone that actually matters, and page you when something breaks.
1.9k+ teams · Free forever tier · No credit card