Every few minutes
A step in the minute field runs the job on every multiple of the step, counted from minute 0 of each hour.
| Schedule | Expression | How cron reads it | Open in the generator |
|---|---|---|---|
| Every minute | * * * * * | Every minute. | Open * * * * * in the generator |
| Every 2 minutes | */2 * * * * | Every 2 minutes. | Open */2 * * * * in the generator |
| Every 5 minutes | */5 * * * * | Every 5 minutes. | Open */5 * * * * in the generator |
| Every 10 minutes | */10 * * * * | Every 10 minutes. | Open */10 * * * * in the generator |
| Every 15 minutes | */15 * * * * | Every 15 minutes. | Open */15 * * * * in the generator |
| Every 20 minutes | */20 * * * * | Every 20 minutes. | Open */20 * * * * in the generator |
| Every 30 minutes | */30 * * * * | Every 30 minutes. | Open */30 * * * * in the generator |
| Every 5 minutes, starting at minute 2 | 2-59/5 * * * * | Every 5th minute from 2 through 59 of every hour. | Open 2-59/5 * * * * in the generator |
| Every 45 minutes (does not work) | */45 * * * * | Every 45th minute. */45 restarts at 0 every hour, so the gap between :45 and :00 is 15 minutes, not 45. | Open */45 * * * * in the generator |
Steps that do not divide 60 restart at the top of each hour, so */45 runs at :00 and :45, 15 minutes apart. To shift a job off the busy top of the hour, give the step a starting minute, as in 2-59/5. GitHub Actions will not run a schedule more often than every 5 minutes.
Hourly and every few hours
Set the minute to a fixed number, or the job runs every minute of the matching hours.
| Schedule | Expression | How cron reads it | Open in the generator |
|---|---|---|---|
| Every hour | 0 * * * * | Every hour at minute 0. | Open 0 * * * * in the generator |
| Every hour at half past | 30 * * * * | Every hour at minute 30. | Open 30 * * * * in the generator |
| Every 2 hours | 0 */2 * * * | At minute 0 past every 2nd hour. | Open 0 */2 * * * in the generator |
| Every 3 hours | 0 */3 * * * | At minute 0 past every 3rd hour. | Open 0 */3 * * * in the generator |
| Every 4 hours | 0 */4 * * * | At minute 0 past every 4th hour. | Open 0 */4 * * * in the generator |
| Every 6 hours | 0 */6 * * * | At minute 0 past every 6th hour. | Open 0 */6 * * * in the generator |
| Every 12 hours | 0 */12 * * * | At minute 0 past every 12th hour. | Open 0 */12 * * * in the generator |
| Every 5 hours (does not work) | 0 */5 * * * | At minute 0 past every 5th hour. */5 restarts at 0 every day, so the gap between 20:00 and 00:00 is 4 hours, not 5. | Open 0 */5 * * * in the generator |
The hour step restarts at midnight in the same way: */5 runs at 00:00, 05:00, 10:00, 15:00 and 20:00, then again at 00:00 after a gap of 4 hours. Writing * in the minute field by mistake, as in * */2 * * *, runs the job 60 times in each matching hour.
Daily
Hours use the 24-hour clock in the time zone of the machine or service that runs the job.
| Schedule | Expression | How cron reads it | Open in the generator |
|---|---|---|---|
| Every day at midnight | 0 0 * * * | At 00:00 every day. | Open 0 0 * * * in the generator |
| Every day at 02:30 | 30 2 * * * | At 02:30 every day. | Open 30 2 * * * in the generator |
| Every day at 06:00 | 0 6 * * * | At 06:00 every day. | Open 0 6 * * * in the generator |
| Every day at noon | 0 12 * * * | At 12:00 every day. | Open 0 12 * * * in the generator |
| Twice a day, at midnight and noon | 0 0,12 * * * | At 00:00 and 12:00 every day. | Open 0 0,12 * * * in the generator |
| Every hour from 01:00 to 05:00 | 0 1-5 * * * | At minute 0 past every hour from 1 through 5. | Open 0 1-5 * * * in the generator |
Where clocks change for daylight saving, the hour they jump over is skipped in spring and the hour they go back over happens twice in autumn. cronie runs a fixed-time job from a skipped hour straight after the change and runs it only once in a repeated hour. The generator flags those runs for any time zone, and a schedule kept in UTC has neither problem.
Weekdays and weekly
In the day-of-week field 0 and 7 are both Sunday, and 1-5 is Monday to Friday.
| Schedule | Expression | How cron reads it | Open in the generator |
|---|---|---|---|
| Every weekday at 09:00 | 0 9 * * 1-5 | At 09:00 on Monday through Friday. | Open 0 9 * * 1-5 in the generator |
| Every Saturday and Sunday at 10:00 | 0 10 * * 0,6 | At 10:00 on Sunday and Saturday. | Open 0 10 * * 0,6 in the generator |
| Every Monday at 09:00 | 0 9 * * 1 | At 09:00 on Monday. | Open 0 9 * * 1 in the generator |
| Every Friday at 17:00 | 0 17 * * 5 | At 17:00 on Friday. | Open 0 17 * * 5 in the generator |
| Every Sunday at midnight | 0 0 * * 0 | At 00:00 on Sunday. | Open 0 0 * * 0 in the generator |
| Every hour in office hours | 0 9-17 * * 1-5 | At minute 0 past every hour from 9 through 17 on Monday through Friday. | Open 0 9-17 * * 1-5 in the generator |
| Every 15 minutes in office hours | */15 9-17 * * 1-5 | Every 15 minutes past every hour from 9 through 17 on Monday through Friday. | Open */15 9-17 * * 1-5 in the generator |
The office-hours lines include the whole of the last hour, so */15 9-17 runs for the last time at 17:45. Use 9-16 to stop at 16:45.
Monthly, quarterly and yearly
Day 1 and month 1 are the first, so 0 0 1 1 * is midnight on 1 January.
| Schedule | Expression | How cron reads it | Open in the generator |
|---|---|---|---|
| The 1st of every month at midnight | 0 0 1 * * | At 00:00 on day 1 of the month. | Open 0 0 1 * * in the generator |
| The 15th of every month at 09:00 | 0 9 15 * * | At 09:00 on day 15 of the month. | Open 0 9 15 * * in the generator |
| The 1st and 15th of every month | 0 0 1,15 * * | At 00:00 on days 1 and 15 of the month. | Open 0 0 1,15 * * in the generator |
| Every quarter, on 1 January, April, July and October | 0 0 1 */3 * | At 00:00 on day 1 of the month in January, April, July and October. | Open 0 0 1 */3 * in the generator |
| Every other day (odd dates) | 0 0 */2 * * | At 00:00 on every 2nd day of the month. | Open 0 0 */2 * * in the generator |
| Once a year, at midnight on 1 January | 0 0 1 1 * | At 00:00 on day 1 of the month in January. | Open 0 0 1 1 * in the generator |
A day-of-month step restarts each month, so */2 runs on the 31st and again on the 1st, one day apart. A job set for the 31st runs only in months that have one. A job for the 30th never runs in February, and one for the 29th runs there only in leap years.
The @ shortcuts
cronie accepts these names in place of the five fields. The Kubernetes CronJob docs list all of them except @reboot, and GitHub Actions accepts none of them.
| Shortcut | Same as | How cron reads it |
|---|---|---|
@hourly | 0 * * * * | Every hour at minute 0. |
@daily | 0 0 * * * | At 00:00 every day. |
@midnight | 0 0 * * * | At 00:00 every day. |
@weekly | 0 0 * * 0 | At 00:00 on Sunday. |
@monthly | 0 0 1 * * | At 00:00 on day 1 of the month. |
@yearly | 0 0 1 1 * | At 00:00 on day 1 of the month in January. |
@annually | 0 0 1 1 * | At 00:00 on day 1 of the month in January. |
@reboot | no fixed time | Once, after the machine starts. |
Schedules cron cannot write in one line
Five fields cover most schedules but not all of them. These are the usual fixes. Each line is a full crontab entry; replace /path/to/job with your command.
Every 30 seconds
* * * * * /path/to/job
* * * * * sleep 30; /path/to/job
Cron counts in whole minutes. Two lines do it: one runs at the start of each minute and the other waits 30 seconds first.
Every 90 minutes
0 0-21/3 * * * /path/to/job
30 1-22/3 * * * /path/to/job
The minute field only goes up to 59, so a step of 90 cannot work. The first line runs at 00:00, 03:00 and so on to 21:00, the second at 01:30, 04:30 and so on to 22:30, which gives a run every 90 minutes all day, 22:30 to 00:00 included.
The last day of the month
0 0 28-31 * * [ "$(date -d tomorrow +\%d)" = 01 ] && /path/to/job
Run on days 28 to 31 and let the command check that tomorrow is the 1st. date -d tomorrow is a GNU date feature, so test it where GNU coreutils is not installed. The backslash stops cron from reading % as a new line.
The first Monday of the month
0 9 1-7 * * [ "$(date +\%u)" = 1 ] && /path/to/job
Putting 1-7 in the day of month and 1 in the day of week does not work, because cron runs on days that match either field. Run on days 1 to 7 and test the weekday in the command instead.
Every other week
0 9 * * 1 [ $(( 1$(date +\%V) \% 2 )) -eq 0 ] && /path/to/job
Run every Monday and let the command skip odd ISO week numbers. The 1 in front turns week 08 into 108, because the shell reads a number with a leading 0 as octal and 08 is not a valid one. Years with 53 weeks put two odd weeks in a row at the turn of the year, so check that January if the gap matters.
Sources
- crontab(5), cronie: fields, steps, the day-of-month or day-of-week rule, @ shortcuts and %
- cron(8), cronie: daylight saving changes
- GitHub Actions: the schedule event (shortest interval 5 minutes)
- GNU coreutils: date conversion specifiers (%d, %u, %V)
- GNU coreutils: relative items in date strings (tomorrow)
- GNU Bash manual: shell arithmetic (a leading 0 means octal)