DEVESSENTIALS

Cron Syntax Explained: */15 * * * * and Other Examples

By · Updated

Cron is the standard Unix scheduler — but its five-field syntax trips up developers every time they need to schedule something non-trivial. This guide walks through every field, every special character, and the common patterns you'll actually reach for.

Cron Expression Format: Quick Reference

A cron expression is five fields separated by spaces, always in this order: minute hour day-of-month month day-of-week. Each field takes a number, * (every value), a list (1,15), a range (1-5) or a step (*/15). The job runs whenever the current time matches every field.

Cron expression fields in order, with allowed values
PositionFieldAllowed valuesSpecial characters
1Minute0–59* , - /
2Hour0–23 (24-hour clock)* , - /
3Day of month1–31* , - /
4Month1–12 or JAN–DEC* , - /
5Day of week0–6 or SUN–SAT (0 = Sunday; most crons also accept 7)* , - /
Cron special characters
CharacterMeaningExample
*Every value of the field* in hour = every hour
,List of values0,30 in minute = :00 and :30
-Inclusive range1-5 in day of week = Mon–Fri
/Step, counted from the start of the range*/15 in minute = 0, 15, 30, 45
Most common cron expressions
ExpressionRunsTry it
* * * * *Every minuteOpen in builder
*/5 * * * *Every 5 minutesOpen in builder
*/15 * * * *Every 15 minutes (:00, :15, :30, :45)Open in builder
0 * * * *Every hour, on the hourOpen in builder
0 */6 * * *Every 6 hours (00:00, 06:00, 12:00, 18:00)Open in builder
0 0 * * *Every day at midnightOpen in builder
0 4 * * *Every day at 04:00Open in builder

Build and test expressions as you go with the visual cron expression builder, or jump straight to the copy-paste cron examples. Cron schedules run on the server clock, so the Unix timestamp converter is handy when you need to check when a job actually fired.

What Is a Cron Expression?

A cron expression is a string of five fields separated by spaces that defines a schedule for recurring jobs. Each field represents a unit of time:

┌───────────── minute (0–59)
│ ┌───────────── hour (0–23)
│ │ ┌───────────── day of month (1–31)
│ │ │ ┌───────────── month (1–12)
│ │ │ │ ┌───────────── day of week (0–6, Sunday=0)
│ │ │ │ │
* * * * *

The cron daemon reads the crontab file and wakes up every minute to check which jobs match the current time. If all five fields match, the command runs.

Special Characters

* — Any value

Matches every value in the field. * * * * * runs every minute of every hour of every day.

/ — Step values

Defines an interval. */15 in the minute field means "every 15 minutes". 2/3 means "starting at 2, every 3 steps" — so 2, 5, 8, 11, ...

- — Ranges

Defines a continuous range. 9-17 in the hour field means hours 9 through 17 inclusive. 1-5 in the day-of-week field means Monday through Friday.

, — Lists

Specifies multiple individual values. 0,15,30,45 in the minute field runs at minutes 0, 15, 30, and 45. MON,WED,FRI in the day-of-week field runs on those three days.

Common Examples

ExpressionDescription
* * * * *Every minute
0 * * * *Every hour, on the hour
0 0 * * *Every day at midnight
0 9 * * 1-59:00 AM on weekdays (Mon–Fri)
*/15 * * * *Every 15 minutes
0 0,12 * * *Midnight and noon every day
0 9 1 * *9:00 AM on the 1st of every month
30 6 * * 16:30 AM every Monday
0 0 1 1 *Midnight on January 1st (yearly)
0 */4 * * *Every 4 hours
5 4 * * sun4:05 AM every Sunday
0 22 * * 1-510:00 PM on weekdays

Extended Cron: @shortcuts

Most modern cron implementations support shorthand strings that replace the five-field syntax:

ShorthandEquivalentMeaning
@reboot(none)Once at startup
@yearly / @annually0 0 1 1 *Once a year, Jan 1
@monthly0 0 1 * *Once a month, 1st day
@weekly0 0 * * 0Once a week, Sunday midnight
@daily / @midnight0 0 * * *Once a day, midnight
@hourly0 * * * *Once an hour, top of hour

Common Cron Mistakes

1. Assuming cron runs in your local time zone

A cron expression has no time zone of its own; the scheduler decides. Classic cron uses the time zone of the machine it runs on, and cloud VMs and containers are usually set to UTC. A job written as 0 9 * * * on a UTC server fires at 09:00 UTC, which is 11:00 in Madrid in summer. Check with timedatectl or date. Cronie (the default on Fedora and RHEL) supports a CRON_TZ=Europe/Madrid line in the crontab; GitHub Actions schedules are always UTC; Kubernetes CronJobs use the controller's time zone unless you set spec.timeZone; AWS EventBridge rules are UTC (EventBridge Scheduler accepts a time zone).

Daylight saving time adds a second trap: in a zone that observes it, a job scheduled between 01:00 and 03:00 can be skipped or run twice on the change-over nights, depending on the cron implementation. Schedule critical jobs in UTC or outside that window.

2. Expecting AND when both day fields are set

When both day-of-month and day-of-week are restricted (neither is *), standard cron runs the job when either matches. 0 9 13 * 5 does not mean "Friday the 13th"; it runs on every 13th of the month and every Friday. If one of the two fields is *, only the other one applies, which is what you usually want. To get a real AND, restrict one field in cron and test the other in the command:

# 09:00 on Friday the 13th only
0 9 13 * * [ "$(date +\%u)" = 5 ] && /usr/local/bin/job.sh

Quartz and AWS EventBridge avoid the ambiguity by requiring ? in one of the two day fields.

3. Expecting */n to be an exact interval

A step restarts at the beginning of its field every time the field rolls over, so it only produces an even interval when n divides the range exactly. */7 in the minute field runs at :00, :07 … :49, :56 and then :00 again, a 4-minute gap. */25 gives :00, :25, :50 and then a 10-minute gap. In the hour field, */5 runs at 00, 05, 10, 15 and 20, then 00 the next day, a 4-hour gap. Use divisors of 60 for minutes (*/5, */10, */15, */20, */30) and divisors of 24 for hours (*/4, */6, */8, */12). An interval that does not fit, such as every 90 minutes, needs two lines:

0  0-21/3 * * *  /usr/local/bin/job.sh   # 00:00, 03:00 … 21:00
30 1-22/3 * * *  /usr/local/bin/job.sh   # 01:30, 04:30 … 22:30

The step also counts from the clock, not from when you saved the crontab or deployed: */15 always means :00, :15, :30 and :45.

4. Mixing up 5-field, 6-field and 7-field formats

Not every "cron" is Unix cron. Copying an expression between systems without checking the field count is one of the most common scheduling bugs:

Cron formats by platform
PlatformFieldsEvery day at 04:00Notes
Linux crontab50 4 * * *Server time zone. Day of week 0–7 (0 and 7 = Sunday).
GitHub Actions50 4 * * *Always UTC. Shortest interval is 5 minutes and runs can start late under load.
Kubernetes CronJob50 4 * * *Controller time zone unless spec.timeZone is set. Also accepts @daily-style macros.
Spring @Scheduled6 (seconds first)0 0 4 * * *Seconds, minutes, hours, day of month, month, day of week. ? is allowed but not required.
Quartz6 or 7 (seconds first, optional year)0 0 4 * * ?? required in day of month or day of week. Day of week 1–7 with 1 = Sunday.
AWS EventBridge6 (year last)cron(0 4 * * ? *)Minutes, hours, day of month, month, day of week, year. UTC. ? required in one day field.

A 6-field expression pasted into a crontab is not rejected: cron reads the first five fields as the schedule and treats the sixth as the start of the command, so 0 0 4 * * * becomes "midnight on the 4th of every month" running a command that starts with *. Going the other way, Spring and Quartz reject a 5-field expression outright. The 0 4 * * * page shows this schedule written out for every platform.

5. Forgetting to escape % in crontab

In a crontab command, an unescaped % is turned into a newline, and everything after the first one is sent to the command's standard input. A date format string is the usual victim:

# Broken: the command is cut off at the first %
0 2 * * * tar czf /backup/site-$(date +%F).tar.gz /var/www

# Fixed: escape every % with a backslash
0 2 * * * tar czf /backup/site-$(date +\%F).tar.gz /var/www

The rule applies to the command field of crontab files (crontab -e, /etc/crontab, /etc/cron.d/), not to scripts that cron calls, so moving anything non-trivial into a script avoids the problem entirely.

6. Leaving * in the minute field

* 2 * * * does not mean "at 2 AM"; it means every minute from 02:00 to 02:59, 60 runs. Always set the minute: 0 2 * * * runs once.

Validation Tips

  • Always test before deploying. Paste the expression into the Cron Builder and check the next run times. An expression like 0 0 31 * * only runs on months that have a 31st day — February, April, June, September, and November will silently skip it.
  • Use absolute paths. Cron runs with a stripped-down environment. Replace python3 script.py with /usr/bin/python3 /home/user/script.py.
  • Make scripts executable. If cron calls a script directly, it needs the execute bit (chmod +x script.sh, or 755). See Linux file permissions explained if the octal notation is unfamiliar.

Build and Validate Cron Expressions Online

If you want to visually build a cron expression and see a plain-English description, the Cron Builder on DevEssentials generates valid cron syntax from a GUI and explains any expression you paste in. No login, 100% client-side.

Looking for a ready-made schedule? See copy-paste cron examples for every 5 minutes, hourly, daily, weekdays and more.

Want one expression explained in depth? See common cron expressions explained, with pages for */15 * * * *, 0 0 * * *, 0 */6 * * * and more, including Quartz and AWS equivalents.


Need to build a cron expression? Use the visual Cron Builder →

Frequently Asked Questions

What is a cron expression?▾

A cron expression is a short string that tells a scheduler when to run a job. The standard Unix format has five fields separated by spaces: minute (0-59), hour (0-23), day of month (1-31), month (1-12) and day of week (0-6, Sunday = 0). For example, 30 2 * * 1-5 means 02:30 Monday to Friday. Each field accepts a single value, * (every value), a list (1,15), a range (9-17) or a step (*/15).

What does */15 * * * * mean in cron?▾

*/15 * * * * runs a job every 15 minutes: at minute 0, 15, 30 and 45 of every hour, every day, which is 96 runs per day. The */15 step counts from the start of the hour, not from when the crontab was saved. The AWS EventBridge equivalent is cron(0/15 * * * ? *) and the 6-field Spring form is 0 */15 * * * *.

What is the difference between 15 * * * * and */15 * * * *?▾

15 * * * * runs once an hour, at minute 15 (00:15, 01:15, 02:15...). */15 * * * * runs four times an hour, at minutes 0, 15, 30 and 45. A plain number is a single value; the slash turns it into a step.

What does 0 */4 * * * mean?▾

0 */4 * * * runs at minute 0 of every fourth hour: 00:00, 04:00, 08:00, 12:00, 16:00 and 20:00, six times a day. Without the leading 0 (* */4 * * *) it would run every minute during those hours, 360 times a day.

What do 0 4 * * * and cron(0 4 * * ? *) mean?▾

Both run once a day at 04:00. 0 4 * * * is the standard crontab form and uses the server's time zone. cron(0 4 * * ? *) is the AWS EventBridge form: it adds a year field at the end, uses ? in the day-of-week field because EventBridge does not allow both day fields to be set, and is evaluated in UTC.

What does 0 0/5 * * * * mean?▾

It is a 6-field expression with a seconds field first, as used by Spring @Scheduled. It means second 0 of every fifth minute: every 5 minutes, at :00, :05, :10 and so on. The 5-field crontab equivalent is */5 * * * *. Quartz would reject it, because Quartz requires ? in either day-of-month or day-of-week, so in Quartz write 0 0/5 * * * ?.

What does 0 0 0/1 1/1 * ? * mean?▾

It is a 7-field Quartz expression (seconds, minutes, hours, day of month, month, day of week, year), the style generated by tools like CronMaker. Second 0, minute 0, every hour starting at 0, every day starting on day 1, every month, any day of week, every year: in short, every hour on the hour. The crontab equivalent is 0 * * * *.

Can a cron expression run every 10 seconds?▾

Not in standard Unix cron: the smallest unit is one minute and there is no seconds field. Schedulers that add a seconds field can: Quartz uses 0/10 * * * * ? and Spring uses */10 * * * * *. On Linux, a systemd timer with OnCalendar=*:*:0/10 (and AccuracySec=1s) also works.

What does */5 mean in a cron expression?▾

The */5 syntax means 'every 5 units'. In the minute field, */5 means every 5 minutes (0, 5, 10, 15, ..., 55). In the hour field, */5 means every 5 hours (0, 5, 10, 15, 20). The * means 'all values' and /5 is the step — so together it reads 'starting from the first value, every 5 steps'.

What is the difference between 0 * * * * and * * * * *?▾

0 * * * * runs once per hour, at minute 0 (top of the hour). * * * * * runs every single minute. The first field is always minutes — setting it to 0 means 'only when the minute is exactly 0', while * means 'every minute'.

How do I run a cron job on weekdays only?▾

Use 1-5 in the day-of-week field (the 5th field). For example, 0 9 * * 1-5 runs at 9:00 AM Monday through Friday. Day values are: 0 = Sunday, 1 = Monday, ..., 6 = Saturday. Some systems also accept 7 for Sunday.

What does @reboot mean in cron?▾

@reboot is a non-standard cron extension supported by most modern cron implementations (Vixie cron, cronie, fcron). It runs the job once when the cron daemon starts, which is typically at system boot. It's equivalent to running a command in a startup script. Other shortcuts: @yearly (0 0 1 1 *), @monthly (0 0 1 * *), @weekly (0 0 * * 0), @daily (0 0 * * *), @hourly (0 * * * *).

Why is my cron job not running at the expected time?▾

The most common cause is timezone confusion. Cron runs in the system timezone of the server, which may differ from your local timezone or UTC. Check the server timezone with timedatectl or date +%Z.

Other common issues: the command works in an interactive shell but fails in cron because cron has a minimal environment (no PATH, no env vars). Always use absolute paths in cron commands (e.g. /usr/bin/python3 instead of python3). Also check /var/log/cron or /var/log/syslog for error output.

Browse all developer guides →