Cron Syntax Explained, With Examples
A standard cron expression has five space-separated fields: minute, hour, day of month, month and day of week. A job runs whenever the current time matches all of them, with one exception: when both day fields are restricted, a match on either one is enough. For example, 30 2 * * 1-5 means 02:30 on Monday to Friday, in the time zone of the machine running the cron daemon.
The five fields
┌───────────── minute (0–59)
│ ┌─────────── hour (0–23)
│ │ ┌───────── day of month (1–31)
│ │ │ ┌─────── month (1–12 or JAN–DEC)
│ │ │ │ ┌───── day of week (0–7 or SUN–SAT; 0 and 7 are both Sunday)
│ │ │ │ │
30 2 * * 1-5 /path/to/command
| Field | Allowed values | Names |
|---|---|---|
| Minute | 0-59 | – |
| Hour | 0-23 | – |
| Day of month | 1-31 | – |
| Month | 1-12 | JAN to DEC |
| Day of week | 0-7 (0 and 7 are Sunday) | SUN to SAT |
Names are the first three letters of the English month or day, and case does not matter. The reference for Linux is the crontab(5) manual page; most Linux distributions ship cronie or a Vixie cron derivative, and the rules below follow those.
Operators: * , - and /
| Operator | Meaning | Example |
|---|---|---|
* | Every value in the field | * * * * * runs every minute |
, | A list of values | 0 6,18 * * * runs at 06:00 and 18:00 |
- | An inclusive range | 0 9-17 * * * runs hourly from 09:00 to 17:00 |
/ | A step through a range or * | */15 * * * * runs at minutes 0, 15, 30 and 45 |
Steps count from the start of the range and restart at each boundary, so they are not a true interval. */7 in the minute field matches minutes 0, 7, 14 … 56 and then 0 again, leaving a four-minute gap across each hour. Similarly 0 */5 * * * runs at 00:00, 05:00, 10:00, 15:00 and 20:00, then again four hours later at midnight. For an even spread, choose a step that divides 60 (minutes) or 24 (hours).
Lists and steps combine with ranges: */15 9-17 * * 1-5 means every 15 minutes from 09:00 to 17:45 on weekdays. Some crontab(5) pages say that ranges and lists of names are not allowed, so 1-5 is more portable than MON-FRI.
The day-of-month and day-of-week rule
This is the part of cron that surprises people most. The crontab(5) page states that if both day fields are restricted, the job runs when either matches. So:
0 8 1-7 * 1 # 08:00 on each of days 1–7 AND on every Monday
# (not "the first Monday of the month")
If either day field is *, only the other one matters. Classic cron has no way to say "first Monday"; the usual workaround is to schedule 0 8 1-7 * * and test the weekday inside the command. When writing that test in a crontab line, remember that an unescaped % in the command is turned into a newline, so date +%u must be written as date +\%u.
One subtlety: Vixie-derived implementations, including cronie, decide whether a day field is restricted by whether it begins with an asterisk. A field such as */2 therefore counts as unrestricted there, and 0 0 */2 * 1 runs only on Mondays that fall on odd-numbered dates. The Cron Expression Parser on this site follows the same rule. Other schedulers may not, so expressions that mix a stepped day field with a day-of-week value are best avoided.
Special strings: @daily, @reboot and friends
| Macro | Equivalent |
|---|---|
@reboot | Once, when the cron daemon starts |
@yearly, @annually | 0 0 1 1 * |
@monthly | 0 0 1 * * |
@weekly | 0 0 * * 0 |
@daily | 0 0 * * * (some implementations also accept @midnight) |
@hourly | 0 * * * * |
@reboot runs when the daemon starts, which is usually but not necessarily at boot.
Common schedules
Every row below was checked with the parsing code used by the Cron Expression Parser, including the next run times it produces.
| Expression | Runs |
|---|---|
* * * * * | Every minute |
*/5 * * * * | Every five minutes |
0 * * * * | Every hour, on the hour |
0 */2 * * * | Every two hours (00:00, 02:00 … 22:00) |
0 0 * * * | Daily at midnight |
30 2 * * * | Daily at 02:30 |
0 6,18 * * * | At 06:00 and 18:00 every day |
0 9 * * 1-5 | 09:00 Monday to Friday |
*/15 9-17 * * 1-5 | Every 15 minutes, 09:00–17:45, weekdays |
0 12 * * 6,0 | Noon on Saturday and Sunday |
0 0 * * 0 | Sunday at midnight (weekly) |
15 14 1,15 * * | 14:15 on the 1st and 15th of each month |
0 0 1 * * | Midnight on the first of each month |
0 0 1 */3 * | Midnight on 1 January, April, July and October |
0 0 1 1 * | Midnight on 1 January |
A frequent mistake is * 2 * * * when "daily at 2am" was meant: it runs every minute from 02:00 to 02:59. Set the minute too, as in 0 2 * * *.
Time zones and daylight saving
Classic cron evaluates schedules in the local time zone of the system or daemon, not of the user who wrote the crontab. cronie also supports a CRON_TZ variable in the crontab to run its entries in a different zone; not every implementation does, so check your manual page before relying on it.
Daylight saving changes mean that a local time such as 02:30 can be skipped or occur twice. Vixie-derived daemons document special handling for clock changes of less than three hours, but behaviour differs between implementations, so the simplest options are to keep servers on UTC or to avoid scheduling important jobs between 01:00 and 03:00 local time. To convert a run time between zones or into a Unix timestamp, use the Unix Timestamp Converter.
Cron in other systems
Many schedulers borrow cron syntax but change the details:
| System | Differences from five-field cron |
|---|---|
| Quartz (Java) | Six or seven fields: seconds first, an optional year last. Day of week is 1–7 with 1 as Sunday. One of the two day fields must be ? (no specific value). Adds L (last), W (nearest weekday) and # (for example 2#1, the first Monday). |
| Kubernetes CronJob | Standard five fields plus macros such as @hourly. The spec.timeZone field sets the zone; without it the schedule follows the time zone of the kube-controller-manager. |
| GitHub Actions | on.schedule takes five-field POSIX cron and is evaluated in UTC. Runs can start late when load is high. |
| AWS EventBridge rules | Written as cron(minutes hours day-of-month month day-of-week year): six fields including a year, no seconds. One day field must be ?; day of week is 1–7 with 1 as Sunday; supports L, W and #. Rules run in UTC; EventBridge Scheduler lets you choose a time zone. |
Check each system's own documentation before copying an expression between them, particularly the day-of-week numbering.
What the Cron Expression Parser accepts
The Cron Expression Parser describes an expression in plain English and lists its next five run times as you type. Based on its code:
- It needs exactly five fields; six- or seven-field Quartz or AWS expressions are rejected with a message giving the number of fields found.
- It accepts
*, lists, ranges and steps, month and day names in any case (including in ranges and lists, such asMON-FRI),7for Sunday, and?, which it treats like*. - It accepts
@yearly,@annually,@monthly,@weekly,@daily,@midnightand@hourly.@rebootis reported as an unknown macro, because it has no run times to show. - It rejects
L,Wand#, out-of-range values (such as minute 60) and ranges that run backwards (such asFRI-MON). - It also accepts a start and step without a range, such as
5/15(minutes 5, 20, 35 and 50). Not every cron implementation accepts this form;5-59/15is the portable way to write it. - Next run times are shown in your browser's local time zone, which may differ from your server's. It looks up to about eight years ahead, so
0 0 29 2 *lists only the leap days in that window, and0 0 31 2 *shows "Never — this date does not occur".
Frequently asked questions
Does standard cron support seconds?
No. Classic cron has minute resolution and five fields. Seconds appear only in schedulers that add a sixth field, such as Quartz.
How do I run a job on the last day of the month?
Standard cron has no L. A common workaround is to run on days 28–31 and have the command check whether tomorrow is the 1st; Quartz and AWS EventBridge support L directly.
Is Sunday 0 or 7?
In Linux cron both 0 and 7 mean Sunday. Quartz and AWS EventBridge number days 1–7 with 1 as Sunday, so the same digit can mean different days in different systems.
Why did my job run on the wrong day?
The usual cause is the day-of-month and day-of-week rule: restricting both fields makes the job run when either matches. The other common cause is a time zone mismatch between where you wrote the schedule and where the daemon runs.