The five fields
Classic cron, as used by Linux crontab, Kubernetes CronJobs and GitHub Actions, reads five fields from left to right. Each field lists the values at which the job may run, and the job runs whenever all fields match the current time. An asterisk means any value.
| Position | Field | Allowed values | Names |
|---|---|---|---|
| 1 | Minute | 0 to 59 | |
| 2 | Hour | 0 to 23 | |
| 3 | Day of month | 1 to 31 | |
| 4 | Month | 1 to 12 | JAN to DEC |
| 5 | Day of week | 0 to 7 (0 and 7 are Sunday) | SUN to SAT |
Try it here: Cron Expression Generator
Open the full tool pageSpecial characters
Four characters cover almost every schedule. They can be combined inside one field, for example 1-5,10 or 0-30/10.
| Character | Meaning | Example | Result |
|---|---|---|---|
| * | Every value | * in the hour field | Every hour |
| , | A list of values | 0,30 in the minute field | At minute 0 and 30 |
| - | A range | 9-17 in the hour field | Every hour from 9 through 17 |
| / | A step | */15 in the minute field | Every 15 minutes: 0, 15, 30, 45 |
| / after a value | Step from a start | 5/20 in the minute field | At minute 5, 25 and 45 |
| @ shortcut | A named schedule | @daily | Same as 0 0 * * * |
Common schedules
These expressions were checked with the generator on this page. Copy the one closest to what you need and adjust the numbers.
| Expression | Runs |
|---|---|
| * * * * * | Every minute |
| */5 * * * * | Every 5 minutes |
| */15 * * * * | Every 15 minutes |
| 0 * * * * | At the start of every hour |
| 30 * * * * | At minute 30 of every hour |
| 0 */6 * * * | Every 6 hours: 0:00, 6:00, 12:00, 18:00 |
| 0 0 * * * | Every day at midnight |
| 0 9 * * * | Every day at 9:00 |
| 0 9,17 * * * | Every day at 9:00 and 17:00 |
| 0 9 * * 1-5 | At 9:00 from Monday through Friday |
| */10 9-17 * * 1-5 | Every 10 minutes during office hours on weekdays |
| 0 22 * * 0,6 | At 22:00 on Saturday and Sunday |
| 0 9 * * 1 | Every Monday at 9:00 |
| 0 0 1 * * | On the first day of every month at midnight |
| 0 0 1,15 * * | On the 1st and 15th of every month |
| 0 0 1 */3 * | On the first day of every third month (quarterly) |
| 0 0 1 1 * | Once a year, on 1 January at midnight |
| 15 2 * * * | Every night at 2:15 |
| 0 12 * 6-8 * | Every day at noon in June, July and August |
| 0 8 1-7 * 1 | Careful: day 1 to 7 or any Monday, see below |
Day of month and day of week together
This is the rule that catches the most people. When both day fields are restricted, classic cron runs on days that match either of them, not both. So 0 8 1-7 * 1 does not mean the first Monday of the month: it runs on days 1 to 7 and also on every Monday. In the same way, 0 0 13 * 5 runs on every 13th and on every Friday, not only on Friday the 13th.
There is one more twist: if one of the two fields starts with an asterisk, as in */2, cron treats it as unrestricted for this rule and both fields must match. 0 0 */2 * 1 therefore runs only on Mondays that fall on an odd day of the month. The generator on this page points out both cases in its explanation.
To run on the first Monday in classic cron, schedule the job for Mondays and let the script exit unless the day of the month is 7 or less. Quartz can express it directly with 2#1.
Time zones and daylight saving
Cron runs in the time zone of the machine or service that executes it. Many servers and cloud services use UTC, GitHub Actions schedules are always in UTC, and Kubernetes CronJobs use the controller's time zone unless you set the timeZone field. Some cron daemons also read a CRON_TZ variable in the crontab.
In zones with daylight saving time, one night a year has no 2:30 and another has 1:30 twice. Most Linux cron daemons run jobs from the skipped hour right after the change and run fixed time jobs only once in the repeated hour, while jobs that run every hour run in both. Other schedulers may skip the run instead. If a job must run exactly once a day, schedule it outside the hours between 1:00 and 3:00, or run the scheduler in UTC. The run list in the generator marks every run that falls on a clock change.
Seconds, Quartz and Spring
Java and some JavaScript schedulers add a seconds field at the start, so their expressions have six fields: 0 */5 * * * * runs every five minutes at second 0. Quartz goes further and changes several rules, which is why a classic expression often fails there.
- Quartz has 6 or 7 fields: seconds, minute, hour, day of month, month, day of week and an optional year.
- Days of the week are numbered 1 to 7 starting with Sunday, so MON is 2. Names such as MON-FRI avoid the confusion.
- One of the two day fields must be ?, which means no specific value. 0 0 9 ? * MON-FRI runs at 9:00 on weekdays.
- L means last: L in the day of month field is the last day of the month, 6L in the day of week field is the last Friday.
- W picks the nearest weekday: 15W runs on the weekday closest to the 15th, LW on the last weekday of the month.
- # picks the nth weekday: 6#3 is the third Friday of the month.
- Spring's @Scheduled also uses six fields with seconds first, but numbers days of the week 0 to 7 like classic cron and does not require ?.
Mistakes to avoid
- Writing * * * * * when you mean once a day. The first field is the minute, so this runs 1440 times a day.
- Expecting */7 in the day of month field to mean every seven days. It means days 1, 8, 15, 22 and 29, and starts again on the 1st.
- Scheduling day 31, 30 or 29. Months without that day are skipped, not moved to the last day.
- Forgetting the time zone. 0 9 * * * on a UTC server runs at 9:00 UTC, which may be night where your users are.
- Using Quartz features such as L or ? in a Linux crontab, or a five field expression in Quartz. The generator converts between the syntaxes when you switch.