Five fields or six
Standard cron is minute, hour, day of month, month, day of week. Quartz, built into Spring and other Java frameworks, adds a sixth field at the front for seconds. The dialect is inferred from the field count.
Timezone matters because of clock changes. "At 03:30" is a different instant in UTC depending on whether daylight saving is in effect that day, so a fixed-local-time schedule has to be evaluated in the zone people read it in, not UTC and not whatever a server is set to.
The dialect support table
Where schedulers differ. Most documentation covers one at a time.
| Symbol | Meaning | Standard cron | Quartz | AWS EventBridge |
|---|---|---|---|---|
* | any value | ✓ | ✓ | ✓ |
, | list, e.g. 1,3,5 | ✓ | ✓ | ✓ |
- | range, e.g. 1-5 | ✓ | ✓ | ✓ |
/ | step, e.g. a slash then 15 | ✓ | ✓ | ✓ |
? | no specific value, day fields only | × | ✓ | ✓ |
L | last day of the month, or last weekday | × | ✓ | × |
# | nth weekday, e.g. the 3rd Friday | × | ✓ | × |
W | nearest weekday to a given day | × | ✓ | × |
Common problems
- Day of month and day of week do not AND together. They OR instead. The classic cron surprise: when both are restricted, the schedule fires whenever either matches, not only when both do.
0 0 1 * 1runs on the 1st of the month and every Monday, not only on a Monday that happens to be the 1st. Set the one you do not care about to a wildcard, or to?in Quartz, to get a plain AND. - "Restricted" means the text does not start with a star. Cron tests the field's first character, not what it works out to, so a step such as
0 0 */2 * MONcounts as a wildcard for the rule above and ANDs: every second day that is also a Monday. Write0 0 1-31/2 * MONfor the same set of days and the same expression ORs instead. - Quartz numbers day of week differently. Standard cron runs 0 to 6 with Sunday as 0; Quartz runs 1 to 7 with Sunday as 1. This tool normalises every numeric day of week to 0 to 6 in both dialects. Writing weekday names (
MON,FRI) in a Quartz expression avoids the ambiguity entirely. - A wall-clock time near a clock change is ambiguous. "01:30" on the day clocks fall back happens twice; "02:30" on the day they spring forward never happens. Every scheduler resolves this differently, so check what yours documents.
Land#cannot be combined with a list.1,Lis invalid. Write a separate rule, or in Quartz put?on the field you are not constraining.
Frequently asked questions
Why does the same expression show a different time in another timezone?
A cron field is a wall-clock time, not an instant, and never carried a timezone. "At 03:30" in Europe/Brussels and in America/New_York are hours apart. Pick the zone the schedule runs in, not necessarily your own.
Does this verify my expression against a real scheduler?
No. It follows the documented grammars, including the differences in the table above, but the scheduler you deploy to is the final authority. A seventh field for year, which some Quartz examples use, is reported as invalid here.
How far ahead does "next 10 runs" search?
8 years, which covers a once-a-year schedule and stops an impossible expression, like day of month 31 locked to February, from searching forever.
What time zone does the schedule run in?
Whatever the machine running it uses, which is the single most common cron surprise. Cron itself has no time zone field, so a job that looks correct locally fires an hour out after a daylight saving change, or in UTC on a server you never set. Check the crontab TZ variable or the scheduler configuration, and prefer UTC for anything coordinated.