Cron builder and explainer
Plain five-field cron is easy. What bites is the timezone the scheduler actually runs in, the day-of-month rule nobody remembers, and the dialect differences between Airflow, Quartz and EventBridge. Type an expression and see the next runs as real instants.
Fields 5
Meaning -
| Next run, local | UTC | Offset | In |
|---|
Field five is a trap
If you set both day-of-month and day-of-week to something other than a star, cron does not require both to match. It fires when either matches. So 0 0 13 * 5 runs on the 13th of every month and also on every Friday, rather than only on a Friday the 13th. This catches people on backup jobs and report schedules, and it is the single most common reason a schedule runs far more often than intended. To get the intersection you have to test the day inside the job, or use a dialect that supports a stricter rule.
A star in either field makes the other one govern normally, which is why the trap only shows up once someone edits a working expression.
Steps count from the range start
In */15 the step is measured from the start of the range, not from the current time. The schedule is fixed and does not shift to follow your last run. That matters when you assume a step expression means "every 15 minutes from whenever it last fired", which it does not.
The timezone belongs to the scheduler
Kubernetes and GitHub Actions run cron in UTC, with no timezone to set. Airflow takes a timezone and a cron expression, and resolves the schedule in that zone. So the same expression means a different instant on each system, and the difference changes twice a year. The offset column above shows that for each run: across a spring-forward boundary the local wall clock jumps, and a job set for a time inside the skipped hour does not run that day at all.
Airflow historically carried explicit workarounds for the autumn fold, where an hour repeats and a job can be scheduled to fire twice or once depending on how the timetable handles it. If a nightly job matters, set it well away from the transition hour rather than testing the edge case in production. Moving a job into the small hours also changes what it costs: batch pricing is half the standard rate as long as the run can wait for a result.
Dialects differ where it costs you
Quartz adds a leading seconds field, so a six-field expression means something different depending on the scheduler reading it. EventBridge numbers days of the week from 1 for Sunday rather than 0, so a day-of-week value copied from a crontab expression lands on the wrong day. Quartz and EventBridge both accept ? to mean "not specified" in one of the two day fields, which is how you escape the either-or rule above. EventBridge also supports L for the last day and # for the nth weekday of a month, and this tool implements both.
W, the nearest weekday to a given day, is parsed but is rarer and its edge behaviour around month boundaries varies by implementation, so treat any result from it as a check rather than a guarantee.