Developer Tools

Cron Expressions Explained With 12 Real Schedules

Five fields, ranges, steps and the day-of-month trap, explained through 12 schedules you can copy, plus what to check before trusting a cron job.

2026-11-067 min readBy ToolHive Team

The five fields, in order

A standard cron expression has five fields separated by spaces. Reading left to right they are the minute (0 to 59), the hour (0 to 23), the day of the month (1 to 31), the month (1 to 12) and the day of the week (0 to 6, where 0 is Sunday; many implementations also accept 7 for Sunday). A star (*) means "every value". A job runs when the current time matches all of the fields, with one exception covered below.

Three pieces of syntax cover most real schedules:

  • A range such as 1-5 means every value from 1 to 5. In the day-of-week field that is Monday to Friday.
  • A step such as */15 means every 15th value, starting from the first. In the minute field it means minutes 0, 15, 30 and 45.
  • A list such as 1,15 means exactly those values, for example the 1st and the 15th.

The easiest way to learn this is to read a lot of examples, so here are twelve.

12 schedules you can copy

#ExpressionWhen it runs
10 9 * * 1-509:00 on weekdays
20 0 * * *Midnight, every day
3*/15 * * * *Every 15 minutes, all day
430 2 * * 002:30 every Sunday
50 */2 * * *On the hour, every 2 hours (00:00, 02:00, 04:00 and so on)
60 0 1 * *Midnight on the 1st of every month
70 8 * * 108:00 every Monday
80 18 * * 518:00 every Friday
90 6 * * 606:00 every Saturday
100 0 1 1 *Midnight on 1 January, once a year
1145 23 * * 023:45 every Sunday
125 */6 * * *At 5 minutes past the hour, every 6 hours (00:05, 06:05, 12:05, 18:05)

Notice the pattern in the first two fields. A fixed minute and a fixed hour mean "at that clock time". A step in the hour field with a fixed minute means "at that minute, every N hours". A star in the minute field means "every minute", which is rarely what you want. * 9 * * * runs 60 times between 09:00 and 09:59, not once at 9.

Building one with the generator

The cron expression generator takes the five fields as one line of comma-separated values, in the order minute, hour, day of month, month, day of week. An empty position means *. It joins them with spaces and prints a short plain-English summary.

For example, typing 0,9,,,1-5 gives 0 9 * * 1-5 and the summary "at 09:00, on weekdays". Typing 30,2,,,0 gives 30 2 * * 0, summarised as "at 02:30, on Sunday". Typing 0,0,1 gives 0 0 1 * *, "at 00:00, on day 1 of the month".

Because commas separate the fields, you cannot type a list inside a single field. If you want the 1st and 15th of the month, write 0 0 1,15 * * by hand. Those commas belong to the cron syntax, not to the tool's input format.

Three traps that cause most wrong schedules

1. Day of month and day of week are combined with OR

If you restrict both the day-of-month and the day-of-week field, traditional cron runs the job when either one matches, not when both do. So 0 9 1 * 1 does not mean "09:00 on the 1st if it is a Monday". It runs at 09:00 on the 1st of every month and at 09:00 on every Monday. People hit this when they try to schedule "the first Monday of the month". The usual workaround is to schedule the job for every Monday and have the script itself exit unless the date is 1 to 7. Behaviour can differ between cron implementations and cloud schedulers, so test with your own system.

2. Steps start from the beginning of the range

*/15 in the minute field gives 0, 15, 30, 45. A step of 7 (*/7) gives 0, 7, 14, 21, 28, 35, 42, 49, 56 and then jumps back to 0 at the next hour, so the gap between 56 and the next run is only 4 minutes. Steps divide evenly into 60 (and 24 for hours) only when the number is a factor: 2, 3, 4, 5, 6, 10, 12, 15, 20, 30 for minutes. For anything else, the spacing is uneven.

3. The time zone belongs to the server, not to you

Cron has no time zone in the expression. A job set for 0 9 * * 1-5 runs at 09:00 in whatever zone the scheduler uses. A server in UTC runs it at 14:30 India time (India is UTC+5:30 and does not observe daylight saving). If you want 09:00 IST on a UTC server, the hour and minute fields need to say 30 3, which is 03:30 UTC. Some cron versions let you set a time zone variable for the crontab, and some cloud schedulers have a time zone setting. Check what your system supports instead of assuming.

Daylight saving time adds another wrinkle for servers in zones that observe it. A job scheduled during the hour that is skipped or repeated in spring and autumn may not run, or may run twice, depending on the implementation. Scheduling sensitive jobs outside the 01:00 to 03:00 local window, or running the server in UTC, avoids the question.

A decision framework for picking a schedule

  1. Start from the business need, not the syntax. Write the sentence first: "every weekday at 9 AM India time".
  2. Convert to the scheduler's time zone. Do this before writing any field.
  3. Prefer fixed times over steps when the exact moment matters. Use steps only for polling or housekeeping jobs where "roughly every N minutes" is fine.
  4. Avoid the top of the hour for heavy jobs if many other jobs share the machine. 7 * * * * spreads load better than 0 * * * *.
  5. Use only one of the two day fields unless you really mean OR.
  6. Make the job safe to run twice and safe to skip once. Cron does not retry a missed run on its own if the machine was off.

Worked example: a nightly backup and a Monday report

Say you want a database backup every night at 01:30 server time and a summary email at 08:00 every Monday. The backup is 30 1 * * *. In the generator you would type 30,1, which gives 30 1 * * * and the summary "at 01:30". The Monday report is 0 8 * * 1, typed as 0,8,,,1, summarised as "at 08:00, on Monday".

If your server runs in UTC but the team reads the report at 08:00 India time, set the report hour and minute to 30 2 instead (08:00 IST is 02:30 UTC), giving 30 2 * * 1. Same Monday, different clock reading.

Job output is often JSON. If a scheduled job writes its result as a single unreadable line, paste it into the JSON formatter to read it. If you merge crontabs from several servers and suspect duplicate entries, the remove duplicate lines tool will drop repeated lines, though it will not tell you which ones overlap in time. To check that a log line matches the pattern you expect before writing a log-based alert, try it in the regex tester.

Limits: what the generator does not do

  • No lists inside a field. Because commas split the fields, 1,15 for day of month cannot be typed in. Write those expressions by hand.
  • The summary is partial. It describes plain times, step values in the minute or hour field, weekdays, weekends and named days. A step in the minute field with a fixed hour, or a step in the month field, may be described loosely or only as the raw expression. For example, the summary for 0 */2 * * * says "every 2 hours" and does not mention that it fires on the hour.
  • It does not validate values. An hour of 99 is not flagged. Check each field against its range.
  • Five-field cron only. Quartz and some cloud schedulers add a seconds field, a year field or special characters, and their expressions will not match what this tool prints.
  • It does not show next run times and does not know your server's time zone.

Treat the summary as a sanity check, not a guarantee. Read the expression yourself, convert the time zone, and watch the first real run before you rely on a job.

#cron#cron expression#scheduling#linux#developer tools