Skip to content
koducathome

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
FieldAllowed valuesNotes
Minute0–59
Hour0–2324-hour clock; 0 is midnight
Day of month1–31Days that do not exist in a month are simply skipped
Month1–12 or jan–decNames are case-insensitive
Day of week0–7 or sun–sat0 and 7 both mean Sunday; 1 is Monday

Special characters and shortcuts

CharacterMeaningExample
*Every value of the field* in the hour field = every hour
,A list of values1,15 in day of month = the 1st and 15th
-An inclusive range1-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.

ExpressionRuns
* * * * *Every minute
*/5 * * * *Every 5 minutes
0 * * * *Every hour, on the hour
30 2 * * *Every day at 02:30
0 9 * * 1-5At 09:00 on weekdays (Monday–Friday)
0 0 * * 0At 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-5Every hour from 09:00 to 17:00 on weekdays
*/15 9-17 * * 1-5Every 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,0At noon on Saturday and Sunday
5 4 * * sunAt 04:05 every Sunday
0 0 1,15 * *At midnight on the 1st and 15th of every month
0 22 * * 1-5At 22:00 on weekdays
0 0 1 * 1At 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:

Last day of the month (GNU date)
0 23 28-31 * * [ "$(date -d tomorrow +\%d)" = "01" ] && /usr/local/bin/month-end-report

The 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 * 1 runs on the 1st of every month and on every Monday — not only on Mondays that fall on the 1st.
  • 0 0 13 * 5 runs on every 13th and every Friday, not just on Friday the 13th.
  • 0 0 * * 1 runs only on Mondays, because the day-of-month field is * and therefore does not take part.
To run only when both conditions are true, restrict one field in cron and check the other in the command — for example, schedule 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_TZ variable in the crontab; Kubernetes CronJobs accept spec.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

PlatformFormatThings to know
Linux crontab (Vixie/cronie)5 fields + commandRuns with a minimal environment; set PATH and use absolute paths
Kubernetes CronJob5 fieldsSupports @hourly-style macros and spec.timeZone
GitHub Actions5 fields, UTC onlyVery frequent schedules may be delayed or skipped under load
Quartz (Java), Spring6–7 fields starting with secondsUses ?, L, W and #; not interchangeable with crontab
AWS EventBridge6 fields including yearUses ? 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

  1. Describe the schedule in words first, including the timezone: "every weekday at 07:30 UTC".
  2. Build the expression in the Cron Generator or write it by hand: 30 7 * * 1-5.
  3. Check the next few run times the generator lists, especially around month ends and weekends.
  4. Install it with crontab -e, and confirm with crontab -l.
  5. 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>&1

Jobs 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 Generator

Frequently 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.