Cron Expression Syntax Explained Simply
Cron expressions look cryptic at first. Five asterisks somehow translate into 'every weekday at 9 AM.' Here's how to read, write, and debug cron expressions.

Cron Expression Syntax Explained Simply
Cron expressions look cryptic at first glance. Five asterisks and numbers separated by spaces somehow translate into "run this job every weekday at 9 AM." If you have ever stared at 0 9 * * 1-5 and wondered what it means, this guide is for you.
We will break down cron expression syntax from the basics to advanced patterns, with plenty of examples along the way. By the end, you will be able to read, write, and debug cron expressions with confidence. Once you have your expressions ready, you can set up cron monitoring in 5 minutes to ensure your jobs run as expected.
Cron Expression Basics
A standard cron expression consists of five fields separated by spaces. Each field represents a unit of time, and together they specify when a job should run.
The Five Fields
* * * * *
| | | | |
| | | | +--- Day of week (0-6, Sunday = 0)
| | | +----- Month (1-12)
| | +------- Day of month (1-31)
| +--------- Hour (0-23)
+----------- Minute (0-59)
Reading from left to right: minute, hour, day of month, month, day of week.
A Simple Example
Let us decode 30 14 * * *:
30- At minute 3014- Of hour 14 (2 PM in 24-hour time)*- Every day of the month*- Every month*- Every day of the week
This expression means: "Run at 2:30 PM every day."
Time is Usually UTC
An important note: most cron systems run in UTC (Coordinated Universal Time) unless configured otherwise. A job scheduled for 0 9 * * * runs at 9 AM UTC, not 9 AM in your local timezone. Always check what timezone your cron daemon is using to avoid surprises.
The Five Fields Explained
Let us look at each field in detail.
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sunday=0)
│ │ │ │ │
* * * * *
Minute (0-59)
The first field specifies which minute of the hour the job runs. Valid values are 0 through 59.
0- At the top of the hour (minute 0)30- At half past the hour45- At 45 minutes past the hour
Hour (0-23)
The second field specifies which hour of the day. Uses 24-hour format.
0- Midnight12- Noon23- 11 PM
Day of Month (1-31)
The third field specifies which day of the month. Valid values are 1 through 31.
1- First of the month15- Middle of the month31- Last day (only runs in months with 31 days)
Month (1-12)
The fourth field specifies which month. Valid values are 1 through 12.
1- January6- June12- December
Day of Week (0-6)
The fifth field specifies which day of the week. On most systems, 0 is Sunday.
0- Sunday1- Monday5- Friday6- Saturday
Special Characters
Cron expressions support special characters that give you flexibility in scheduling.
Asterisk (*) - Every Value
The asterisk means "every" or "any." It matches all possible values for that field.
* * * * * # Every minute of every hour of every day
0 * * * * # Every hour (at minute 0)
0 0 * * * # Every day at midnight
Comma (,) - Multiple Values
Use commas to specify multiple specific values.
0 9,17 * * * # At 9 AM and 5 PM daily
0 0 1,15 * * # On the 1st and 15th of each month
0 0 * * 1,3,5 # On Monday, Wednesday, and Friday
Hyphen (-) - Range of Values
Use hyphens to specify a range of consecutive values.
0 9-17 * * * # Every hour from 9 AM to 5 PM
0 0 1-7 * * # First 7 days of each month
0 0 * * 1-5 # Monday through Friday
Slash (/) - Step Values
Use slashes to specify step intervals. The format is start/step or */step for "every N."
*/5 * * * * # Every 5 minutes
*/15 * * * * # Every 15 minutes
0 */2 * * * # Every 2 hours (at minute 0)
0 0 */3 * * # Every 3 days
You can also combine with ranges:
0 9-17/2 * * * # Every 2 hours between 9 AM and 5 PM (9, 11, 1, 3, 5)
Common Examples with Explanations
Here are expressions you will encounter and use frequently.
Every Minute
* * * * *
Runs every single minute. Useful for testing but rarely appropriate for production.
Every 5 Minutes
*/5 * * * *
The /5 means "every 5th minute." Runs at 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, and 55 minutes past each hour.
Every Hour
0 * * * *
Runs at minute 0 of every hour. Note that * * * * * would run every minute, not every hour.
Daily at Midnight
0 0 * * *
Runs at 00:00 (midnight) every day. One of the most common patterns for daily maintenance tasks.
Daily at a Specific Time
30 4 * * *
Runs at 4:30 AM daily. Common for backups that should complete before business hours.
Weekdays at 9 AM
0 9 * * 1-5
Runs at 9 AM Monday through Friday. The 1-5 in the day-of-week field covers Monday (1) through Friday (5).
Every Sunday at 4:30 AM
30 4 * * 0
Runs at 4:30 AM every Sunday. Sunday is 0 in most cron implementations.
First of Each Month
0 0 1 * *
Runs at midnight on the first day of every month. Common for monthly reports or billing tasks.
Quarterly (First Day of Quarter)
0 0 1 1,4,7,10 *
Runs at midnight on January 1, April 1, July 1, and October 1.
Weekday Gotchas
The day-of-week field causes the most confusion. Here are the common pitfalls.
Sunday Can Be 0 or 7
On most standard cron implementations, Sunday is 0. However, some systems (notably some versions of Vixie cron and newer systems) also accept 7 as Sunday.
0 0 * * 0 # Sunday (standard)
0 0 * * 7 # Sunday (on some systems)
For maximum compatibility, use 0 for Sunday.
Monday Through Friday
0 9 * * 1-5
This is the standard way to specify weekdays. Monday is 1, Friday is 5.
Weekend Only
0 9 * * 0,6
Sunday (0) and Saturday (6). Note the comma separating the two values.
Be Careful with Day-of-Month and Day-of-Week
When you specify both day-of-month and day-of-week (non-asterisk values in both fields), most cron implementations run the job when EITHER condition is met, not when both are met.
0 0 15 * 1 # Runs on the 15th AND on every Monday
This runs on every Monday AND on the 15th of every month, not just on Mondays that fall on the 15th.
Month and Day Names
Some cron implementations allow three-letter abbreviations for months and days.
Month Names
0 0 1 JAN * # January 1st
0 0 1 JAN,APR,JUL,OCT * # Quarterly
Day Names
0 9 * * MON # Every Monday
0 9 * * MON-FRI # Weekdays
Recommendation: Use Numbers
While names can be more readable, numbers are more portable across different cron implementations. If you are writing cron expressions that might be used on different systems, stick with numbers.
Advanced Patterns
Once you are comfortable with the basics, you can create more complex schedules.
Every 2 Hours
0 */2 * * *
Runs at the top of every even-numbered hour (0:00, 2:00, 4:00, etc.).
Every Hour During Business Hours
0 9-17 * * *
Runs at minute 0 of each hour from 9 AM to 5 PM.
Every Other Day
0 0 */2 * *
Runs at midnight every other day (1st, 3rd, 5th, etc. of the month).
Specific Days
0 0 * * 1,4
Runs at midnight on Mondays and Thursdays only.
Twice Daily
0 9,21 * * *
Runs at 9 AM and 9 PM daily.
Every 10 Minutes During Business Hours
*/10 9-17 * * 1-5
Runs every 10 minutes, but only between 9 AM and 5 PM on weekdays.
Last Day of Month (Approximation)
Cron does not have a "last day of month" syntax. A common workaround:
0 0 28-31 * *
This runs on the 28th through 31st, so it hits the last day of every month. However, it also runs on other days. A better approach is to check the date in your script:
0 0 28-31 * * [ "$(date +\%d -d tomorrow)" = "01" ] && /path/to/script.shCommon Mistakes
Avoid these frequent errors when writing cron expressions.
Forgetting That Some Fields Are 0-Indexed
Hours and minutes start at 0, but days of month and months start at 1. Days of week start at 0 (Sunday).
0 0 0 * * # WRONG: Day 0 doesn't exist
0 0 1 * * # CORRECT: First day of month
Timezone Confusion
Your cron daemon probably runs in UTC. A job at 0 9 * * * runs at 9 AM UTC, which might be 4 AM or 2 AM in your local timezone depending on where you are and whether daylight saving time is in effect.
Always confirm your cron daemon's timezone and account for it in your expressions.
Day-of-Week vs Day-of-Month Conflict
As mentioned earlier, specifying both creates an OR condition, not an AND condition.
# Intended: 15th of month if it's a Monday
# Actual: 15th of month OR any Monday
0 0 15 * 1
If you need both conditions to be true, handle the logic in your script instead.
Wildcard Overuse
Using asterisks everywhere creates jobs that run very frequently:
* * * * * # Every minute - are you sure?
Always double-check that your expression does not run more often than intended. For more guidance on avoiding scheduling pitfalls, see our cron job best practices for reliability.
Testing Your Expressions
Before deploying a cron expression to production, verify it does what you expect.
Use a Cron Expression Validator
Online tools can show you when your expression will next run. Enter your expression and see the next 5-10 scheduled times. If they do not match your expectations, adjust and test again.
Check "Next N Runs" Before Deploying
When you set up a cron job, look at the calculated next runs:
- Next run: 2026-01-24 00:00:00 UTC
- Following run: 2026-01-25 00:00:00 UTC
- Then: 2026-01-26 00:00:00 UTC
If these times match your intention, you are good to deploy.
Watch for Edge Cases
Test expressions around edge cases:
- Month boundaries (end of January, end of February)
- Daylight saving time transitions
- Leap years
Quick Reference Table
Here is a handy reference for common schedules:
| Schedule | Expression |
|---|---|
| Every minute | * * * * * |
| Every 5 minutes | */5 * * * * |
| Every 15 minutes | */15 * * * * |
| Every 30 minutes | */30 * * * * |
| Every hour | 0 * * * * |
| Every 2 hours | 0 */2 * * * |
| Every day at midnight | 0 0 * * * |
| Every day at 3 AM | 0 3 * * * |
| Every day at 9 AM and 5 PM | 0 9,17 * * * |
| Every weekday at 9 AM | 0 9 * * 1-5 |
| Every Sunday at midnight | 0 0 * * 0 |
| Every Saturday at 2:30 AM | 30 2 * * 6 |
| First of month at midnight | 0 0 1 * * |
| Every Monday at 9 AM | 0 9 * * 1 |
| Twice a month (1st and 15th) | 0 0 1,15 * * |
| Every quarter (Jan, Apr, Jul, Oct 1st) | 0 0 1 1,4,7,10 * |
| Yearly (January 1st) | 0 0 1 1 * |
Conclusion
Cron expressions are a powerful way to specify schedules, but their compact syntax can be confusing at first. Remember the five fields (minute, hour, day of month, month, day of week), learn the special characters (asterisk, comma, hyphen, slash), and always test your expressions before deploying.
Key takeaways:
- Read expressions left to right: minute, hour, day, month, weekday
- Asterisk means "every," comma means "and," hyphen means "through," slash means "every Nth"
- Watch out for timezone differences, usually UTC
- Be careful with day-of-month and day-of-week together (OR logic, not AND)
- Always validate expressions before deploying to production
When you set up cron monitoring with Cron Crew, you can enter your cron expression and see exactly when your job is expected to run. This validation helps catch expression mistakes before they cause missed runs or unexpected behavior. For a comprehensive overview of monitoring strategies, read our complete guide to cron job monitoring. And when you are ready to compare tools, check out our cron monitoring pricing comparison. Sign up for a free account and try it with your next scheduled job.