HomeArticlesHow ToCron Expressions
HOW TO

How to Use Cron Expressions

Learn how to write and read cron expressions — the 5-field syntax, common scheduling patterns, and how to validate an expression before deploying.

Updated 2026-06-27

Free calculators used in this guide

Cron Expression GeneratorCron Expression Validator

Overview

Cron expressions are the short, five-field strings that tell a scheduler exactly when to run a recurring job — from a nightly backup to a weekly report email. The syntax is compact enough to be confusing at first glance, but it follows a small, consistent set of rules once you understand the order of fields and the handful of special characters used to build patterns.

This guide walks through reading and writing the standard 5-field cron syntax, the wildcards and operators that build common patterns, and the tools to validate or generate an expression before it goes anywhere near production. Use the Cron Expression Validator to confirm any expression's behavior, and the Cron Expression Generator for schedules that are harder to write correctly by hand.

What You Need

Before writing a cron expression, know:

  • The exact schedule you want — stated in plain language first ("every weekday at 6 PM," "the 1st of every month at midnight")
  • Your system's cron implementation — standard 5-field Unix cron, or an extended format like Quartz that adds seconds and sometimes year
  • The timezone your scheduler runs in — server local time or an explicitly configured timezone
  • Whether day-of-week starts at 0=Sunday or 1=Monday in your specific system, since this convention is not universal

Step 1: Understand the 5-Field Syntax

A standard cron expression has exactly five fields, separated by spaces, always in this order:

minute  hour  day-of-month  month  day-of-week
0-59    0-23  1-31           1-12   0-6 (0 = Sunday)

Each field can be a specific number, a wildcard, or a more complex pattern built from the special characters covered in Step 2. For example, the expression 30 14 * * * means minute 30, hour 14, every day of the month, every month, every day of the week — which translates to "every day at 2:30 PM."

Reading a cron expression left to right, in field order, is the most reliable way to avoid misinterpreting it — never assume the order based on what "sounds natural," since some other scheduling systems do order fields differently.


Step 2: Use Wildcards and Special Characters

Four characters build almost every cron pattern you will ever need:

  • Asterisk (*) — means "every" value for that field. * * * * * runs every single minute.
  • Comma (,) — creates a list of specific values. 1,15 in the day-of-month field means the 1st and the 15th of the month.
  • Hyphen (-) — creates an inclusive range. 1-5 in the day-of-week field means Monday through Friday (assuming the common 0=Sunday, 1=Monday convention).
  • Slash (/) — creates a step value, meaning "every Nth value starting from the field's minimum." */15 in the minute field means every 15 minutes: 0, 15, 30, 45.

These four characters can be combined within a single field. For example, 0,30 combined with a range like 9-17 in the hour field — written as part of a full expression 0,30 9-17 * * * — runs at the top and bottom of every hour between 9 AM and 5 PM.


Step 3: Write Common Scheduling Patterns

A small set of patterns covers the vast majority of real-world scheduling needs:

Schedule Expression
Every day at midnight 0 0 * * *
Every 15 minutes */15 * * * *
Every Monday at 9 AM 0 9 * * 1
First day of every month at midnight 0 0 1 * *
Every weekday at 6 PM 0 18 * * 1-5

Notice the pattern: the leftmost fields (minute, hour) are usually specific numbers when you want a precise time, while the rightmost fields (day-of-month, month, day-of-week) stay as wildcards unless you specifically need to restrict the day or month. Building expressions by starting with the time-of-day fields and working outward to the day-restriction fields is a reliable way to construct them correctly from scratch.


Step 4: Validate Your Expression Before Deploying

Even simple-looking cron expressions are easy to get subtly wrong — a misplaced field, an inverted range, or a day-of-week numbering mismatch can all silently schedule a job for the wrong time. Before deploying any expression to production, run it through the Cron Expression Validator, which checks syntax correctness and shows the next several scheduled run times in human-readable form.

Seeing the actual upcoming run times — not just a syntax-valid checkmark — is the only reliable way to confirm the expression does what you intended. A syntactically valid expression can still run at completely the wrong time if, for example, you intended "every weekday" but wrote a range that actually includes the weekend due to a numbering mismatch.


Step 5: Generate Complex Schedules

Some schedules are difficult or impossible to express cleanly using only the five basic fields and four operators — "the last day of the month," "every other Tuesday," or "the second Friday of each quarter" all require either non-standard extensions or external logic that pure cron syntax cannot express on its own.

For these less common patterns, use the Cron Expression Generator to describe the schedule in plain terms and receive a correctly constructed expression — or, where standard cron genuinely cannot express the pattern, guidance on the application-level logic needed to supplement it (such as checking the date inside the job itself before deciding whether to actually execute the task).


Common Mistakes to Avoid

Confusing day-of-month and day-of-week field order across different systems. While the standard 5-field order is minute, hour, day-of-month, month, day-of-week, not every scheduling system follows this exactly — Quartz, for example, uses a 6 or 7-field format that adds a seconds field at the start and an optional year field at the end, shifting everything else over by one position. Always check your specific cron implementation's documentation rather than assuming the generic 5-field order applies universally.

Off-by-one errors with day-of-week numbering. Some systems number day-of-week starting at 0=Sunday, while others start at 0=Monday or use 1=Sunday — and mixing up these conventions silently shifts every day-restricted schedule by one day. Before deploying any expression using the day-of-week field, verify your specific system's convention against its documentation, and confirm using the validator's human-readable preview rather than assuming the most common convention applies.

Timezone confusion between server local time and UTC. Most cron daemons execute based on the server's local system time, not UTC, unless a scheduler is explicitly configured to use a fixed timezone. This causes two common failure modes: a job silently shifting by one hour after a daylight saving time transition in regions that observe DST, and a job running at an unexpected hour after being migrated to a server in a different timezone. Document the intended timezone alongside every cron expression, and prefer UTC-based scheduling configurations where your platform supports it, to avoid DST-related drift entirely.


Formula & Methodology

Underneath the syntax, a cron daemon's matching logic is simple: once every minute, it reads the current system time and checks it against every registered expression's five fields. If the current minute matches the minute field, the current hour matches the hour field, and so on for all five fields — treating any wildcard as an automatic match — the daemon triggers that job's execution. This per-minute polling is why standard cron has an inherent one-minute scheduling resolution; sub-minute scheduling requires a different tool or a 6-field format with an added seconds field, such as Quartz.

The one subtlety that catches most users by surprise is how day-of-month and day-of-week interact when both fields are restricted away from their wildcard default. Intuitively, many people expect an AND relationship — "run only when both the date and the weekday match." In practice, most standard cron implementations apply an OR relationship instead: the job runs if either field's condition is satisfied. The expression 0 0 1,15 * 1 therefore runs at midnight on the 1st of the month, on the 15th of the month, AND on every Monday — not only on Mondays that happen to land on the 1st or 15th. This OR behavior is specified in the original cron design and persists across most modern implementations, but it is rarely intuitive on first encounter, which is exactly why previewing actual upcoming run times through a validator — rather than reasoning about the fields in isolation — is the safest way to confirm an expression behaves as intended before it reaches production.

Frequently Asked Questions

A standard cron expression has five fields in this order: minute (0-59), hour (0-23), day-of-month (1-31), month (1-12), and day-of-week (0-6, where 0 is Sunday). For example, 0 9 * * 1 means minute 0, hour 9, any day of month, any month, and weekday 1 (Monday) — so it runs every Monday at 9:00 AM. Some systems, such as Quartz scheduler, use 6 or 7 fields by adding seconds and sometimes year, so always confirm your specific implementation before assuming the standard 5-field layout.
The asterisk is a wildcard meaning "every possible value" for that field. In the expression */15 * * * *, the asterisks in the hour, day-of-month, month, and day-of-week fields mean the schedule applies during every hour, every day, every month, and every day of the week — only the minute field is restricted, to every 15 minutes. An asterisk in every field, * * * * *, would run the job every single minute.
Use the step value syntax in the minute field: */15 * * * *. The slash followed by a number means "every Nth value starting from the field's minimum," so */15 in the minute field (which ranges 0-59) triggers at minute 0, 15, 30, and 45 of every hour. The same step syntax works in any field — */2 in the hour field would mean every 2 hours.
Use a range in the day-of-week field: 0 18 * * 1-5 runs at 6:00 PM Monday through Friday, since 1-5 represents the range from Monday to Friday in the standard convention where 1=Monday. Always verify your system's day-of-week numbering before deploying, since some implementations use 0=Monday or 1=Sunday instead of the more common 0=Sunday, 1=Monday convention.
A comma creates a list of specific values, such as 1,15 in the day-of-month field meaning the 1st and 15th of the month. A hyphen creates an inclusive range, such as 1-5 in the day-of-week field meaning Monday through Friday. A slash creates a step value, such as */15 meaning every 15 units starting from the field's minimum. These three operators can also be combined within a single field, such as 1-5,10 to mean a range plus one extra value.
A cron daemon checks the current time once every minute and compares it against every scheduled expression's five fields. If the current minute, hour, day-of-month, month, and day-of-week all match what the expression specifies (accounting for wildcards), the daemon executes the associated job. This means cron has effectively a one-minute resolution in the standard 5-field format — you cannot schedule something to run at the 30-second mark without a Quartz-style 6-field expression that adds a seconds field.
Most standard cron implementations treat day-of-month and day-of-week as an OR condition when both are restricted (not wildcards) — meaning the job runs if either condition is satisfied, not only when both are satisfied simultaneously. For example, 0 0 1,15 * 1 runs at midnight on the 1st and 15th of the month AND on every Monday, not only on Mondays that happen to fall on the 1st or 15th. This OR behavior surprises many users who expect an AND relationship.
Most cron daemons run using the server's local system time, not UTC, unless explicitly configured otherwise through environment variables or a timezone-aware scheduler. This becomes a problem when a server's timezone changes, during daylight saving time transitions in regions that observe DST, or when a job is migrated between servers in different timezones — the same cron expression can silently start running at a different real-world time. Always document and verify which timezone your cron jobs assume.
Standard 5-field cron syntax has no native way to express "last day of the month" because month lengths vary, but some implementations (such as Quartz and certain Linux cron extensions) support an "L" character in the day-of-month field for this purpose. For systems without this extension, a common workaround is scheduling the job for day 28-31 combined with application-level logic that checks whether tomorrow's date rolls over into a new month before actually running the task.
Use a dedicated validator that parses the expression syntax and shows the next several scheduled run times in human-readable form, so you can visually confirm the schedule matches your intent before it goes live. The [Cron Expression Validator](/cron-expression-validator/) checks syntax correctness and previews upcoming run times, which catches both outright syntax errors and subtler logical mistakes — like an unintended OR between day-of-month and day-of-week — before they cause a job to run at the wrong time in production.
Writing a cron expression by hand works well for common, simple patterns like "every day at midnight" or "every 15 minutes," but becomes error-prone for less common schedules such as "every other Tuesday" or schedules combining multiple specific days and times. A [Cron Expression Generator](/cron-expression-generator/) lets you specify your intended schedule in plain terms and produces the correct syntax automatically, reducing the risk of a subtle field-ordering or range mistake that would otherwise only surface once the job runs at the wrong time.
Yes, by combining comma-separated lists with other operators within a single field. For example, 0 9,13,18 * * * runs at exactly 9:00 AM, 1:00 PM, and 6:00 PM every day — three distinct times specified in one hour field using commas. This is different from a step value like */4, which creates evenly spaced intervals; comma-separated lists let you specify exact, unevenly spaced times within the same field.

Related Articles

GUIDE

Developer Toolbox Guide — Essential Online Tools

HOW TO

How to Generate a UUID

HOW TO

How to Write a robots.txt File

HOW TO

How to Create a sitemap.xml

COMPARISON

Regex vs String Methods — When to Use Which