How to Read and Write a Cron Expression
Read the five cron fields, write ranges, steps and names, find the schedule you need, and avoid the day-of-month and day-of-week, step and time zone surprises.
A cron expression has five fields separated by spaces: minute, hour, day of month, month and day of week, in that order. So * * * * * runs every minute, */5 * * * * every five minutes and 0 9 * * 1-5 at 09:00 on weekdays. Paste any expression into the Cron Expression Explainer to read it in plain English and see when it runs next.
0 9 * * 1-5 | | | | | | | | | +- day of week (0-7 or SUN-SAT) | | | +--- month (1-12 or JAN-DEC) | | +----- day of month (1-31) | +------- hour (0-23) +--------- minute (0-59)
The syntax below follows crontab(5), and each example was run through the explainer.
What do the five fields of a cron expression mean?
| Field | Allowed values | Meaning |
|---|---|---|
| 1. minute | 0 to 59 | The minute of the hour |
| 2. hour | 0 to 23 | The hour of the day, on a 24 hour clock |
| 3. day of month | 1 to 31 | The day of the month |
| 4. month | 1 to 12, or JAN to DEC | The month of the year |
| 5. day of week | 0 to 7, or SUN to SAT | 0 and 7 are both Sunday; Monday is 1 |
The job runs when the minute, the hour and the month all match, and the day matches by the rule in the section on the two day fields. A field is a single value, or a comma separated list of values, ranges and steps, with no spaces inside it.
What does * * * * * mean?
Each * means "every value this field allows". Five of them mean every minute of every hour of every day, so the job runs once a minute, all the time. The explainer reads it as "Every minute". Replace a star with a number to narrow it: 30 * * * * is "At minute 30 past every hour".
How do I use lists, ranges, steps and names?
| Symbol | Meaning | Example |
|---|---|---|
* | Every value the field allows | * * * * * is "Every minute" |
, | A list of values | 0 9,17 * * * is "At 09:00 and 17:00 every day" |
- | A range, including both ends | 0 9-17 * * 1-5 is "Every hour, on the hour, from 09:00 through 17:00 on weekdays" |
/ | A step through * or a range | */15 * * * * is "Every 15 minutes", and 0 9-17/2 * * * is "At 09:00, 11:00, 13:00, 15:00 and 17:00 every day" |
Steps
A step is written after * or after a range. */15 is every 15th value from the start of the field, and 9-17/2 is every second value from 9 to 17. crontab(5) describes steps only after * and after a range, and the explainer rejects a step on a single number such as 5/15. Write 5-59/15 for "every 15 minutes starting at minute 5", which the explainer reads as "At minutes 5, 20, 35 and 50 past every hour".
Names
The month and the day of week can be written as the first three letters of the name, in any case: JAN, mon, Fri. The explainer also accepts them in ranges and lists, such as MON-FRI or JAN,APR,JUL,OCT, and the version of crontab(5) linked above allows that too. Check the manual of the cron you run, or write numbers.
Sunday is 0 and 7
The day of week takes 0 to 7, and both 0 and 7 are Sunday, so 0 0 * * 0 and 0 0 * * 7 are the same schedule. 0 0 * * 5-7 is Friday through Sunday.
What are the most common cron schedules?
| Expression | Schedule | The explainer says |
|---|---|---|
| * * * * * | Every minute | Every minute |
| */5 * * * * | Every 5 minutes | Every 5 minutes |
| */15 * * * * | Every 15 minutes | Every 15 minutes |
| 0 * * * * | Every hour | Every hour, on the hour |
| 0 */2 * * * | Every 2 hours | Every 2 hours |
| 0 0 * * * | Every day at midnight | At 00:00 every day |
| 0 9,17 * * * | Twice a day | At 09:00 and 17:00 every day |
| 0 9 * * 1-5 | Weekdays at 09:00 | At 09:00 on weekdays |
| 0 12 * * MON,WED,FRI | Monday, Wednesday and Friday at noon | At 12:00 on Monday, Wednesday and Friday |
| 0 0 * * 0 | Every Sunday at midnight | At 00:00 on Sunday |
| 0 0 1 * * | The first of every month | At 00:00 on day 1 of the month |
| 0 0 1 */3 * | The first day of each quarter | At 00:00 on day 1 of the month in January, April, July and October |
| 0 0 1 1 * | Once a year, on 1 January | At 00:00 on day 1 of the month in January |
What happens when both the day of month and the day of week are set?
When neither day field starts with *, a day matches if either field matches. The crontab(5) example is 30 4 1,15 * 5: 04:30 on the 1st and the 15th of each month, plus every Friday. From Monday 26 October 2026, the explainer lists Friday 30 October, Sunday 1 November, Friday 6 November, Friday 13 November and Sunday 15 November.
It is not "the first Monday"
0 9 1-7 * 1 looks like "the first Monday of the month", but it runs on days 1 to 7 and on every Monday. Its runs from 26 October 2026 are every day from 1 to 7 November, then Monday 9, 16, 23 and 30 November. Five-field cron has no syntax for the first Monday.
A field that starts with * counts as unrestricted
If either day field starts with *, even with a step such as */10, both have to match. 0 0 */10 * 1 runs on a Monday that is also day 1, 11, 21 or 31 of the month: the explainer says "on days 1, 11, 21 and 31 of the month, but only on Monday", and from 26 October 2026 the first runs are Monday 21 December and Monday 11 January.
A field that covers everything
A day field that lists every value is not the same as *. 0 0 1-31 * 1-5 looks like "weekdays", but day 1 to 31 matches every day, so it runs every day, weekends included. The explainer reads it as "At 00:00 every day".
Why does */7 not run every 7 minutes?
A step counts from the start of the range each time it comes round, and it does not carry on from the last run. */7 * * * * runs at minutes 0, 7, 14, 21, 28, 35, 42, 49 and 56 of every hour. After 10:56 the next run is 11:00, only four minutes later, and then 11:07. Only a step that divides the range evenly, such as */5 or */15 for minutes, gives an even interval.
The same happens with days: 0 0 */2 * * is "every other day" only within a month. It runs on days 1, 3, 5 and so on up to 31, so after 31 January the next run is 1 February, the very next day.
And a day that a month does not have never matches. 0 0 31 * * runs only in months with 31 days: from 1 October 2026 it runs on 31 October, 31 December, 31 January, 31 March and 31 May, and skips November, February, April and June. 0 0 31 2 * never runs, and the explainer says so: "This schedule never runs: February has no day 31."
What are the @daily and @hourly macros?
A macro is a shortcut written in place of the five fields:
| Macro | Same as | Meaning |
|---|---|---|
| @yearly | 0 0 1 1 * | Once a year. @annually is the same. |
| @monthly | 0 0 1 * * | Once a month |
| @weekly | 0 0 * * 0 | Once a week, on Sunday |
| @daily | 0 0 * * * | Once a day. @midnight is the same. |
| @hourly | 0 * * * * | Once an hour |
- The explainer reads these macros in any case (
@DAILYworks) and shows the five fields a macro stands for. @rebootruns once when the system starts, so it has no schedule. The explainer says so instead of describing it.- crontab(5) lists
@dailyand not@midnight, so check that your cron accepts@midnightbefore you use it.
Which time zone does a cron expression use?
None. An expression only says when, by the clock of whatever runs it. crontab(5) lets a crontab have its own time zone with the CRON_TZ variable. Check your scheduler's documentation for its own setting, and find out which zone it uses before you rely on a local time.
The explainer shows the next five runs in UTC, which it starts on, or in the Local time zone of your browser, with a switch between them. It does not know the time zone of your server and does not read CRON_TZ.
Daylight saving time
In Local mode, a time that does not exist because the clocks went forward is left out of the list. In New York the clocks went forward from 02:00 to 03:00 on Sunday 8 March 2026, so 30 2 * * * has no 02:30 that day. In a browser set to New York time, the explainer skips it and lists 9 March next. That matches crontab(5), which says that non-existent times, such as the missing hours of a daylight saving change, "will never match", so a job set for one does not run, and that a time that happens twice makes the job run twice. The explainer lists a time that happens twice, such as 01:30 on 1 November 2026 in New York, once.
cron(8) describes it differently: when the clock moves forward, jobs that run at a specific time and would have run in the skipped interval are run immediately, and when it moves back, the same job is not run twice. The two man pages disagree, so on a day when the clocks change, check what your own scheduler does and trust that over any list, including the explainer's.
How is a Quartz cron expression different?
Quartz, a Java scheduling library, writes its expressions with 6 or 7 fields: seconds first and an optional year last. It also has its own symbols and day numbers, so a Quartz expression is not a cron expression with extra fields.
| Five-field cron | Quartz | |
|---|---|---|
| Fields | 5, from the minute to the day of week | 6 or 7: seconds first, an optional year last |
| Day of week | 0 to 7 or SUN to SAT. Sunday is 0 and 7, Monday is 1 | 1 to 7 or SUN to SAT. Its examples use 2 for Monday and 6 for Friday, so 1 is Sunday |
| The two day fields | A day matches if either field matches, unless one starts with * | One of the two has to be ? |
| Extra symbols | None | ? L W # |
To turn a Quartz expression into five fields, drop the seconds and the year, replace ? with *, and recheck the day numbers. Quartz's 0 0 12 * * ? (noon every day) becomes 0 12 * * *, which the explainer reads as "At 12:00 every day". Symbols such as L (last day) and # (the nth weekday) have no five-field equivalent.
What does the Cron Expression Explainer reject?
The explainer reads the five standard fields and the macros above. It names the field that is wrong, and says what it did not understand:
| Expression | Problem | What the explainer says |
|---|---|---|
| 60 * * * * | A value out of range | Invalid minute field: 60 is not in the range 0 to 59 |
| 5/15 * * * * | A step on a single number | Invalid minute field: a step needs * or a range in front of it, such as 5-59/15 |
| */0 * * * * | A step of zero | Invalid minute field: the step "0" must be a whole number of 1 or more |
| 5-1 * * * * | A range that ends before it starts | Invalid minute field: the range "5-1" ends before it starts |
| 0 0 * * * * | Six fields (seconds first) | Expected 5 fields (minute, hour, day of month, month, day of week) but found 6. Seconds and year fields (Quartz style) are not supported. |
| @reboot | A macro with no schedule | @reboot runs once at startup, so it has no schedule to explain. |
| @every5m | A macro that does not exist | Unknown macro "@every5m". Use @hourly, @daily, @weekly, @monthly or @yearly. |
| 0 0 L * * | A Quartz symbol | Invalid day of month field: "L" is not a valid value |
Jenkins' H is not supported either.
Try the Cron Expression Explainer
Open the Cron Expression Explainer and type an expression. It shows:
- In plain English, with a button to copy the sentence, and a note when you used a macro or set both day fields.
- Field by field, a table of what each of the five fields allows.
- The next 5 runs, in UTC or your local time zone. A schedule that can never run says so.
- Example buttons for the common schedules, so you can start from one and change it.
- Everything runs in your browser, and nothing you type is uploaded.
How to read and write a cron expression
1. Write the five fields in order
Put the minute, hour, day of month, month and day of week on one line, separated by spaces. Use * for any value, so * * * * * runs every minute.
2. Narrow each field with lists, ranges, steps and names
Use a comma for a list (9,17), a hyphen for an inclusive range (9-17), a slash for a step (*/15 or 9-17/2) and three-letter names for the month and the weekday (MON-FRI).
3. Check the day-of-month and day-of-week rule
When neither day field starts with *, a day matches if either field matches. When one of them starts with *, both have to match.
4. Read it back in the Cron Expression Explainer
Paste the expression into the explainer to see it in plain English, field by field, with the next five run times in UTC or your local time.
5. Check the time zone where the job will run
An expression has no time zone of its own. It fires by the clock of the system that runs it, so confirm which time zone that scheduler uses before you rely on a local time.
// Frequently Asked Questions
How do I run a cron job every 5 minutes?
Use */5 * * * *. The */5 in the minute field is a step of 5 starting from 0, so it runs at minutes 0, 5, 10 and so on up to 55 of every hour. The Cron Expression Explainer reads it as "Every 5 minutes".
Is Sunday 0 or 7 in cron?
Both. The day-of-week field takes 0 to 7, and 0 and 7 are both Sunday, so 0 0 * * 0 and 0 0 * * 7 are the same schedule. You can also write SUN.
Why did my monthly cron job skip some months?
A day that a month does not have never matches. 0 0 31 * * runs only in the months that have 31 days, so it is skipped in February, April, June, September and November. Standard five-field cron has no "last day of the month" syntax.
Can cron run a job every 10 seconds?
Not with five fields: the smallest unit is a minute. Schedulers that use a Quartz-style expression add a seconds field at the start, which the Cron Expression Explainer does not read.
Is my cron expression sent to a server?
No. Parsing, describing and working out the run times all happen in your browser. Nothing you type is uploaded.