CCronExplain
Get CronExplain

CronExplain/Guides

How to Interpret Cron Expressions: A Plain-English Guide

Learn to read cron syntax instantly. Understand fields, nicknames, and next-fire times with clear examples for developers and ops teams.

September 29, 2026 · 5 min read

A cron expression tells a scheduler exactly when to run a task by specifying minute, hour, day, month, and weekday constraints. The expression */15 9-17 * * 1-5 means the task runs every 15 minutes between 9 AM and 5 PM, Monday through Friday. You interpret these fields left-to-right, treating asterisks as "every value allowed" and hyphens as inclusive ranges.

Understanding the Five-Field Structure

Standard cron expressions consist of five fields separated by spaces. Each field restricts when the job runs, and the job executes only when all fields match the current time. The order is fixed: minute, hour, day of month, month, day of week.

Consider the expression */15 9-17 * * 1-5. Break it down field by field:

  1. */15: Run every 15 minutes. The asterisk means "every minute," and /15 divides that into steps of 15. Valid minutes are 0, 15, 30, and 45.
  2. 9-17: Run only during hours 9 through 17. This covers 9 AM to 5 PM in 24-hour format. Hour 18 (6 PM) is excluded because the range ends at 17.
  3. *: Run on every day of the month. No restriction on the date number.
  4. *: Run every month. No restriction on January through December.
  5. 1-5: Run only on weekdays. Day 1 is Monday, day 7 is Sunday. Saturday (6) and Sunday (7) are excluded.

The intersection of these rules means the job fires at :00, :15, :30, and :45 past every hour from 9 AM to 5 PM, but only on Monday through Friday. If today is Saturday, the job does not run. If today is Monday at 8 PM, the hour field rejects it because 20 is outside the 9–17 range.

Decoding Special Characters and Ranges

Three characters control how values are selected: asterisk, hyphen, and slash. Understanding their interaction prevents common scheduling errors.

The asterisk * matches every valid value in that field. In the minute field, * means every minute from 0 to 59. In the hour field, * means every hour from 0 to 23. It acts as a wildcard that imposes no restriction.

The hyphen - defines an inclusive range. 9-17 includes both endpoints: hour 9 and hour 17 are valid. This differs from some programming languages where ranges are exclusive at the upper bound. In cron, both ends are included.

The slash / creates a step interval. */15 in the minute field means "start at the beginning of the range and increment by 15." Combined with an asterisk, it covers the full range in steps. You can also combine slash with a range: 9-17/2 means every two hours starting from hour 9, resulting in hours 9, 11, 13, 15, and 17. Hour 10 is skipped because it is not reachable by stepping 2 from 9.

A common mistake is placing the slash before the range. */15 is correct. 15/* is invalid syntax in standard cron. Another error is assuming ranges wrap around midnight. 22-2 does not mean "from 10 PM to 2 AM." It means hours 22, 23, 0, 1, and 2. To cover a night shift properly, you may need two separate entries or accept that the range includes early morning hours.

Using Vixie Cron Nicknames

Some cron implementations support shorthand nicknames that replace common patterns. These are not part of the original Unix cron specification but appear in many Linux distributions and container platforms. They save typing and reduce errors for frequent schedules.

NicknameEquivalent ExpressionMeaning
@hourly0 * * * *At minute 0 of every hour
@daily0 0 * * *Midnight every day
@weekly0 0 * * 0Midnight Sunday
@monthly0 0 1 * *Midnight on the first day of every month
@yearly0 0 1 1 *Midnight January 1
@rebootN/AOnce when the system boots

These nicknames are case-sensitive in most implementations. @Daily may fail where @daily succeeds. If your scheduler rejects a nickname, fall back to the equivalent five-field expression. Not all environments support them. Kubernetes CronJob, for example, accepts standard fields but may not recognize @hourly depending on the controller version. Check your platform’s documentation before relying on nicknames for critical schedules.

Verifying Next Fire Times in Your Timezone

Cron expressions are interpreted in the local timezone of the machine running the scheduler. This causes confusion when teams span multiple regions. An expression like 0 9 * * * fires at 9 AM server time, not necessarily the user’s local time.

To verify behavior, compute the next few fire times manually. Take */15 9-17 * * 1-5 and assume today is Tuesday, March 12. The current time is 8:50 AM. The hour field allows 9 through 17. The minute field allows 0, 15, 30, 45. The next valid combination after 8:50 is 9:00. The subsequent times are 9:15, 9:30, 9:45, 10:00, continuing until 17:45. The last fire time of the day is 5:45 PM. At 6 PM, the hour field rejects further executions until the next day.

If your server runs in UTC and you are in New York (UTC-5), the expression 0 9 * * * fires at 4 AM your time. To fix this, either adjust the hour field to match your local expectation (0 14 * * * for 2 PM New York when server is UTC) or configure the scheduler to use your timezone explicitly. Most modern schedulers allow setting a timezone in the configuration file or environment variable. When timezone handling is unclear, use a tool that shows the next firing times in your browser’s local timezone to confirm the schedule behaves as expected before deploying. You can paste expressions into CronExplain to see the plain-English meaning and the next 10 firing times adjusted to your current timezone.

Building Complex Schedules Visually

Complex expressions often combine multiple constraints. Instead of writing them from memory, build them incrementally. Start with the minute field, then hour, then date fields. Each addition narrows the window.

Suppose you need a backup job that runs every 30 minutes on weekdays between 8 AM and 6 PM, but skips holidays in December. The base expression is */30 8-18 * * 1-5. To add holiday logic, cron itself has limited capability. You might restrict months to 1 and 12, yielding */30 8-18 * 1,12 1-5. This runs only in January and December. For finer control, combine cron with conditional logic inside the script, since cron fields cannot express "skip if holiday."

When building by hand, test each layer. Does */30 8-18 * * * fire correctly? Yes, every half-hour from 8 AM to 6 PM daily. Now add the weekday restriction: */30 8-18 * * 1-5. Confirm it skips weekends. Then add month restrictions if needed. This incremental approach catches typos early.

Visual builders help by showing the resulting expression as you adjust dropdowns for minute, hour, day, month, and weekday. You see the plain-English sentence update live: "Every 30 minutes between 8 AM and 6 PM on weekdays." This immediate feedback prevents off-by-one errors in hour ranges and confirms that weekday numbering matches your expectation (Monday as 1 versus Sunday as 0). Once satisfied, copy the generated expression into your configuration file.

Do it in CronExplain

Everything in this guide works in the browser — open the tool and try it on your own input.

Open CronExplain →

Questions people also ask

What is the difference between 5-field and 6-field cron expressions?

Standard cron uses five fields (minute, hour, day, month, weekday), while Quartz Scheduler and some Java-based tools use six fields by adding seconds as the first field. If your environment supports six fields, the format is seconds, minute, hour, day, month, weekday; otherwise, stick to the standard five-field format.

Does cron use UTC or local time for scheduling?

Cron schedules run based on the local timezone configured on the server hosting the scheduler. This means a job set for 9 AM will fire at 9 AM server time, which may differ from your local time if the server and your workstation are in different time zones.

How do I handle daylight saving time changes in cron?

Most cron implementations adjust automatically to the server's local timezone rules, so a job set for 9 AM will still run at 9 AM local time after clocks change. However, if your server uses UTC, the job time remains fixed relative to UTC and does not shift with daylight saving adjustments in your local region.

Can I use @daily instead of writing out the full expression?

Yes, if your scheduler supports Vixie cron nicknames, @daily is equivalent to `0 0 * * *` and runs at midnight every day. Note that not all platforms support these shortcuts, so check your specific environment's documentation to ensure compatibility before relying on them.

More guides