How to Understand Cron Expressions (with 18 Practical Examples)
Learn the five cron fields, special characters and day-of-month/day-of-week OR rules, with 18 tested schedule examples and tips on timezones and DST.
By the koducat teamUpdated 6 min read
The five fields of a cron expression
Cron is the classic Unix job scheduler, and its schedule syntax is now used far beyond Unix — in Kubernetes CronJobs, CI systems, cloud schedulers and application libraries. A standard cron expression has five fields separated by spaces. A job runs at every minute where all the fields match the current time (with one important exception for the two day fields, covered below).
┌───────────── 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)
│ │ │ │ │
* * * * * command to run| Field | Allowed values | Notes |
|---|---|---|
| Minute | 0–59 | |
| Hour | 0–23 | 24-hour clock; 0 is midnight |
| Day of month | 1–31 | Days that do not exist in a month are simply skipped |
| Month | 1–12 or jan–dec | Names are case-insensitive |
| Day of week | 0–7 or sun–sat | 0 and 7 both mean Sunday; 1 is Monday |
Special characters and shortcuts
| Character | Meaning | Example |
|---|---|---|
* | Every value of the field | * in the hour field = every hour |
, | A list of values | 1,15 in day of month = the 1st and 15th |
- | An inclusive range | 1-5 in day of week = Monday to Friday |
/ | A step through a range | */15 in minutes = 0, 15, 30, 45 |
Steps start at the beginning of the range, not at the current time: */7 in the minute field fires at minutes 0, 7, 14 … 56 and then again at 0, so the gap across the hour is only 4 minutes. If you need a true "every N minutes" interval that does not divide 60, use a scheduler with interval support instead.
Vixie cron and its descendants (including cronie, common on Linux) also accept shortcut strings in place of the five fields: @yearly (or @annually), @monthly, @weekly, @daily (or @midnight), @hourly and @reboot, which runs once when the cron daemon starts. Support for these varies outside classic cron, so check your platform.
15+ practical cron examples
Each of these uses the standard five-field syntax. Paste any of them into the Cron Generator to see the next run times.
| Expression | Runs |
|---|---|
* * * * * | Every minute |
*/5 * * * * | Every 5 minutes |
0 * * * * | Every hour, on the hour |
30 2 * * * | Every day at 02:30 |
0 9 * * 1-5 | At 09:00 on weekdays (Monday–Friday) |
0 0 * * 0 | At midnight every Sunday |
0 0 1 * * | At midnight on the 1st of every month |
15 14 1 * * | At 14:15 on the 1st of every month |
0 */6 * * * | Every 6 hours: 00:00, 06:00, 12:00, 18:00 |
0 9-17 * * 1-5 | Every hour from 09:00 to 17:00 on weekdays |
*/15 9-17 * * 1-5 | Every 15 minutes from 09:00 to 17:45 on weekdays |
0 0 1 1 * | At midnight on 1 January |
0 0 1 */3 * | At midnight on the 1st of January, April, July and October |
0 12 * * 6,0 | At noon on Saturday and Sunday |
5 4 * * sun | At 04:05 every Sunday |
0 0 1,15 * * | At midnight on the 1st and 15th of every month |
0 22 * * 1-5 | At 22:00 on weekdays |
0 0 1 * 1 | At midnight on the 1st of the month and every Monday (see below) |
Standard cron has no syntax for "the last day of the month". A common workaround runs the job on days 28–31 and lets the command check whether tomorrow is the 1st. Note that % must be escaped as \% inside a crontab line, because cron treats an unescaped % as a newline:
0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/month-end-reportThe day-of-month / day-of-week OR rule
This is the most common cron surprise. In Vixie cron and most compatible implementations, if both the day-of-month and day-of-week fields are restricted (neither is *), the job runs when either matches — not when both do.
0 0 1 * 1runs on the 1st of every month and on every Monday — not only on Mondays that fall on the 1st.0 0 13 * 5runs on every 13th and every Friday, not just on Friday the 13th.0 0 * * 1runs only on Mondays, because the day-of-month field is*and therefore does not take part.
0 9 * * 5 (every Friday) and exit early unless date +%d is 13. Some schedulers, such as Quartz, avoid the ambiguity by requiring ? in one of the two fields.Timezones and daylight saving time
Classic cron interprets schedules in the system's local timezone. That makes 30 2 * * * ambiguous on days when daylight saving time changes: in many zones 02:30 does not exist on the spring-forward day and occurs twice on the fall-back day. Implementations handle this differently — some run the job once, some skip it, some run it twice — so do not rely on any particular behaviour.
- Run servers in UTC where possible. UTC has no daylight saving changes, so every schedule is unambiguous.
- Avoid 01:00–03:00 local time for important jobs if you must use a zone with DST.
- Check per-job timezone support. cronie supports a
CRON_TZvariable in the crontab; Kubernetes CronJobs acceptspec.timeZone; GitHub Actions scheduled workflows always use UTC. - Convert when reading logs. The Timestamp Converter helps translate between UTC and local times when checking when a job really ran.
Cron dialects on different platforms
| Platform | Format | Things to know |
|---|---|---|
| Linux crontab (Vixie/cronie) | 5 fields + command | Runs with a minimal environment; set PATH and use absolute paths |
| Kubernetes CronJob | 5 fields | Supports @hourly-style macros and spec.timeZone |
| GitHub Actions | 5 fields, UTC only | Very frequent schedules may be delayed or skipped under load |
| Quartz (Java), Spring | 6–7 fields starting with seconds | Uses ?, L, W and #; not interchangeable with crontab |
| AWS EventBridge | 6 fields including year | Uses ? in one day field, similar to Quartz |
Before copying an expression between systems, count the fields. A six-field expression pasted into a five-field system will either be rejected or, worse, be read with every field shifted by one position.
Building and testing a schedule step by step
- Describe the schedule in words first, including the timezone: "every weekday at 07:30 UTC".
- Build the expression in the Cron Generator or write it by hand:
30 7 * * 1-5. - Check the next few run times the generator lists, especially around month ends and weekends.
- Install it with
crontab -e, and confirm withcrontab -l. - Redirect output to a log so failures are visible, as shown below, and check the log after the first scheduled run.
# m h dom mon dow command
30 7 * * 1-5 /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1Jobs that work in your shell but fail under cron almost always depend on environment variables, a relative path or the current directory. For more automation helpers, browse the DevOps tools category.
Try it now with the free Cron Expression Generator & Explainer — it runs in your browser.
Open Cron GeneratorFrequently asked questions
Does cron support seconds?
Standard cron does not; its smallest unit is one minute. Six-field formats with a seconds field are used by schedulers such as Quartz and Spring, but they are not valid in a crontab.
Is Sunday 0 or 7 in cron?
Both. Most implementations accept 0 and 7 for Sunday, and Monday is 1. Using three-letter names such as sun and mon avoids the confusion.
Why did my cron job run on the wrong day?
The usual causes are the day-of-month/day-of-week OR rule, a server timezone you did not expect, or a step value like */7 that restarts at the beginning of each hour or day. Check the next run times in a cron generator to confirm.
What timezone does a cron job use?
Classic cron uses the system timezone of the machine running the daemon. Some platforms let you set a timezone per job; others, such as GitHub Actions, always use UTC.