How to read a cron expression
Cron is the scheduling syntax used by Linux and the great majority of job schedulers. It's made up of several space-separated fields, each describing one dimension of time. The key to reading it isn't memorising syntax — it's grasping that the fields are joined by "and". The job runs only when every field matches at once.
What the five fields are
- Field 1 — minute: 0–59
- Field 2 — hour: 0–23, using the 24-hour clock, so 3pm is written 15
- Field 3 — day of month: 1–31
- Field 4 — month: 1–12
- Field 5 — day of week: 0–7, where both 0 and 7 mean Sunday (some implementations make 1 the Monday, so watch out)
If the scheduler supports second-level precision (Spring's @Scheduled(cron=...), Quartz), a seconds field is prepended, making six fields. That's why pasting the same expression in different places can make it "run more often than expected" — a five-field pattern parsed as six shifts every field along by one.
The five notations
- A specific value:
30means the 30th minute. - A range:
9-18matches 9 through 18 inclusive at both ends. - A list:
1,3,5means any of those three values. - A step:
*/5means every 5th value starting from the beginning;10-40/5means every 5 minutes from 10 to 40. - A wildcard:
*means "anything goes in this field".
These can be mixed, so 0,30 9-17 * * 1-5 means "on the hour and half hour, between 9am and 5pm, Monday to Friday".
Breaking down a real expression
Take */5 9-18 * * 1-5 field by field:
- Minute
*/5: every 5 minutes (0, 5, 10 … 55) - Hour
9-18: 9am to 6pm - Day
*: any date - Month
*: any month - Day of week
1-5: Monday to Friday
Together that reads: "every 5 minutes from 9:00 to 18:55 on weekdays". Refreshing data frequently during business hours and stopping after close is a very common pattern.
The three traps people hit most
- When both "day of month" and "day of week" are restricted, it's "or", not "and". This is the most counter-intuitive rule in cron. Writing
0 0 13 * 5might be intended as "the 13th, if it's a Friday", but its actual meaning is "the 13th of the month or every Friday" — more than ten times as often. To express "and" you need a different approach, or a check inside the script. - Don't use
*/nfor an exact period across the 24-hour boundary.*/7in the minute field is really 0, 7, 14 … 56, and then the next hour restarts at 0 — so after minute 56 only 4 minutes pass. For a strict period (every 7 minutes exactly) use the seconds field or a dedicated scheduler. - There is no year field. Standard cron cannot express "only in 2026". Limit the year inside the job script, or use an extended syntax that supports it (Quartz does; standard crontab does not).
How it differs from systemd timers
On modern Linux you can use systemd timers instead of crontab. The syntax differs: crontab is one line, while systemd needs both a .service and a .timer file. systemd's advantages are a more readable format such as OnCalendar, a record of the last run's result, and a catch-up policy for missed runs (Persistent=true). For machines that aren't on 24 hours a day, systemd timers are more reliable — cron simply doesn't run jobs it missed while the machine was off.
Time zones matter too: cron uses the server's local time. Containers default to UTC in most cases, so your carefully tested "8am every day" can become 4pm in a container. Always verify the time zone setting after deploying.
How to verify an expression
Don't do it in your head. Paste the expression into the box above and the tool lists the next 10 run times. Checking the times is the fastest verification there is — and it exposes traps like the day/day-of-week OR at a glance: if you write 0 0 13 * 5, the listed times will include both every 13th of the month and every Friday, and the problem is immediately obvious.
Parsing happens entirely in your browser, with no network access needed.
Frequently asked questions
What time is 0 6 * * *?
6am every day. The first field 0 means minute zero, the second field 6 means 6 o'clock, and the remaining three are wildcards with no restriction. It's one of the most common patterns there is.
Are @daily-style macros supported?
Standard crontab supports a set of macros: @daily (midnight each day), @hourly, @weekly, @monthly, @yearly, @reboot (once after boot). This tool focuses on standard numeric expressions; substitute the macro yourself — @daily is 0 0 * * *.
Why does 7 work for the day of week?
Because both 0 and 7 are defined as Sunday, so either works. To mean Monday, though, use 1 — don't write 8. Some systems define the day of week as 1 to 7 with 1 as Sunday, so always confirm when moving across platforms.
The predicted times don't match when it actually runs?
Check the time zone first. Containers and cloud functions mostly default to UTC, which is 8 hours off Beijing time. Next, confirm whether the scheduler expects five fields or six — adding or omitting one shifts the whole string.
Can it calculate every run time for the next year?
This tool lists 10 by default, which is plenty to validate the logic. To tally totals (to assess job load, say), use the scheduler's own analysis tools or compute it yourself server-side.