Skip to content
Quasar Tools Logo

Cron Resolver: Understanding Cron Expressions

A complete guide to cron expressions — syntax, field rules, special characters, common schedules, and how to resolve, validate, and test cron jobs for free.

DH
Tutorials & How-Tos12 min read2,700 words

Cron expressions look cryptic at first glance — five space-separated fields packed with asterisks, numbers, slashes, and commas. But there is a consistent logic to every field, and once you understand it, reading and writing cron schedules becomes straightforward. This guide breaks down every part of cron syntax, explains the special characters, shows the most common schedule patterns, and covers the tools that resolve, validate, and simulate cron expressions before you deploy them.

5Standard cron fieldsminute, hour, dom, month, dow
15+Built-in schedule presetsin the Crontab Expression Builder
12moSimulation horizonin the Interactive Cron Scheduler

What is a cron expression?

A cron expression is a string of five (or sometimes six) space-separated fields that defines a recurring schedule for automated tasks. The format was invented with the Unix cron daemon in the early 1970s and has remained essentially unchanged ever since. Today it is used in Linux crontab files, CI/CD pipelines like GitHub Actions and GitLab CI, cloud schedulers like AWS EventBridge and Google Cloud Scheduler, container orchestrators like Kubernetes CronJob, and application frameworks including Spring and Quartz.

The anatomy of a cron expression

The standard five-field format is:

cron expression format
text
┌─────────── minute        (0–59)
│ ┌───────── hour          (0–23)
│ │ ┌─────── day of month  (1–31)
│ │ │ ┌───── month         (1–12)
│ │ │ │ ┌─── day of week   (0–7, Sunday = 0 or 7)
│ │ │ │ │
* * * * *   command to execute

Fields are read left to right: minute, hour, day-of-month, month, day-of-week. The expression "0 9 * * 1-5" fires at 09:00 on every weekday. Each field can hold a single value, a comma-separated list, a range, a step, a wildcard, or a combination. Understanding these operators is the entire skill of reading cron.

Note

Some platforms use a 6-field format that adds a seconds field at position 0 (before minutes). Spring Scheduler and Quartz use this format. AWS EventBridge and most Unix cron daemons use 5 fields. Always check which format your target platform expects — an expression written for one may silently produce the wrong schedule on another.

Cron expression syntax field by field

Each field has a defined range of valid integer values. Values outside the valid range produce an error or silent misconfiguration depending on the cron implementation. Understanding the valid range for each field is the foundation of reading any cron expression.

Field valid ranges

  • Minute — 0 to 59. Value 0 is the top of the hour; value 59 is one minute before the next hour.
  • Hour — 0 to 23. Uses 24-hour format: 0 is midnight, 12 is noon, 23 is 11 PM.
  • Day of month — 1 to 31. Days are 1-indexed. Some months have fewer days — February has 28 or 29, April/June/September/November have 30.
  • Month — 1 to 12. January is 1, December is 12. Some implementations also accept three-letter abbreviations: JAN, FEB, MAR, etc.
  • Day of week — 0 to 7. Both 0 and 7 represent Sunday. Monday is 1, Saturday is 6. Some implementations support MON, TUE, WED, THU, FRI, SAT, SUN.

How field interactions work

The five fields are evaluated together as a logical AND — the job runs when all non-wildcard fields match simultaneously. "0 9 15 * *" fires at exactly 09:00 on the 15th of every month. The critical exception is when both day-of-month and day-of-week are non-wildcard values — in that case, most cron daemons fire if EITHER condition is true (a logical OR), not both. This is a notorious source of unexpected behavior.

Warning

The day-of-month / day-of-week OR behavior is one of the most common cron pitfalls. "0 9 1 * 1" does NOT mean "the first Monday of the month at 09:00" — it means "09:00 on the 1st of the month, OR 09:00 on any Monday." Use a script or a managed scheduler with calendar-aware logic if you need true "first Monday of the month" semantics.

Special characters explained

Cron's power comes from its special characters — the operators that turn fixed values into flexible schedule patterns. Mastering these six operators covers virtually every scheduling pattern you will encounter.

The six core operators

CharacterNameExampleMeaning
*Wildcard* in minuteEvery valid value (0–59 for minutes)
,List1,15,30 in minuteAt minutes 1, 15, and 30
-Range1-5 in dowMonday through Friday (days 1 to 5)
/Step*/15 in minuteEvery 15 minutes (0, 15, 30, 45)
?No-spec? in domNo specific value (Quartz/Spring only)
@Macro@dailyShorthand aliases (@daily = 0 0 * * *)

Combining operators

Operators can be combined within a single field. "0,30 9-17 * * 1-5" means "at minutes 0 and 30 of every hour from 9 AM to 5 PM, Monday through Friday." Step syntax can also be applied to a range: "0-30/5" in the minute field means every 5 minutes from minute 0 to minute 30 (0, 5, 10, 15, 20, 25, 30). The Cron to Human-Readable Translator breaks down any combination into plain English with field-by-field explanations.

Tip

When reading an unfamiliar cron expression, parse each field from left to right and translate it independently. Minute field first, then hour, then day-of-month, then month, then day-of-week. Read each non-asterisk field as a constraint: "only when minute = X", "only when hour = Y", etc. The result reads as a sentence when assembled in reverse order from right to left.

Common cron schedule patterns

The majority of real-world cron schedules fall into a handful of recurring patterns. Knowing these patterns by sight means you can read most production crontabs without a reference.

  1. "* * * * *" — Every minute. The most frequent possible schedule. Used for heartbeat checks and monitoring.
  2. "*/5 * * * *" — Every 5 minutes. Common for polling jobs and cache warmers.
  3. "0 * * * *" — Every hour on the hour. Standard for hourly batch processes.
  4. "0 0 * * *" — Daily at midnight (UTC). The default for daily cleanup jobs.
  5. "0 9 * * 1-5" — 9 AM every weekday. Standard business-hours schedule.
  6. "0 0 1 * *" — Midnight on the 1st of every month. Monthly billing runs, report generation.
  7. "0 0 1 1 *" — Midnight on January 1st. Annual jobs — license renewals, year-end reports.
  8. "0 0 * * 0" — Midnight every Sunday. Weekly maintenance windows.

Building custom schedules from patterns

Most complex schedules are combinations of these patterns. "0 2 * * 6,0" means "2 AM on Saturday and Sunday" — the weekend maintenance window. "*/10 8-18 * * 1-5" means "every 10 minutes from 8 AM to 6 PM, weekdays only." If you know the target schedule in plain English, the Crontab Expression Builder lets you configure each field visually and generates the correct expression with a human-readable confirmation and the next five run times.

Crontab Expression Builder

Build cron expressions visually with 15 presets, 5 field modes, instant human-readable description, and next 5 run time preview — free, no signup.

Open tool

How to build and validate cron expressions

Writing a cron expression from scratch and hoping it is correct is risky. A single transposed field or a misunderstood operator can cause a job to fire at completely wrong times — or never fire at all. These tools eliminate that risk.

1

Write or select your expression

Open the Crontab Expression Builder and either type your expression directly or choose from the 15 built-in presets. Each preset covers a common schedule pattern (every minute, hourly, daily, weekdays, monthly) and can be adjusted using the visual field controls without touching the raw expression.

2

Validate for syntax errors

Paste the expression into the Cron Expression Validator. It checks each field against its valid range, validates range boundaries (start must be less than end), confirms step values are non-zero, and flags macros that are not supported by standard 5-field crontab. Each error comes with a line-level message explaining what the parser expected.

3

Translate to plain English

Run the validated expression through the Cron to Human-Readable Translator. The output is a full plain-English sentence describing the schedule — "At 2:30 AM, on Monday, Wednesday, and Friday" — plus a field-by-field breakdown. If the description does not match your intent, revise the expression before deploying.

4

Simulate the next 12 months of runs

For scheduled jobs where timing matters — billing runs, data exports, maintenance windows — open the Interactive Cron Scheduler and simulate the expression over the next 12 months. The calendar view shows monthly run density, and the timeline shows exact timestamps. Confirm the schedule fires on the expected dates before merging the configuration to production.

Cron Expression Validator

Validate 5-field cron syntax, ranges, steps, list values, and macros with instant field-level diagnostics — browser-local, free, no signup.

Open tool

Cron in CI/CD and cloud schedulers

Cron syntax is used far beyond the Linux crontab. Modern CI/CD and cloud platforms have all adopted the same 5-field format, but each has its own quirks around timezone handling, macro support, and minimum interval restrictions.

Platform-by-platform differences

PlatformFieldsTimezoneMacrosMin interval
Linux crontab5System local✓ All 6Every minute
GitHub Actions5UTC only✗ NoneEvery 5 min (enforced 15 min drift)
GitLab CI5UTC only✓ PartialEvery minute
AWS EventBridge5 or 6UTC only✗ NoneEvery minute
Google Cloud Scheduler5 or unixAny IANA tz✓ SomeEvery minute
Kubernetes CronJob5Cluster tz✗ NoneEvery minute
Spring Scheduler6JVM default✓ YesEvery second

GitHub Actions cron scheduling

GitHub Actions uses standard 5-field cron syntax but always runs in UTC. If you want a job at 9 AM Eastern time (UTC-5), you write "0 14 * * *". GitHub Actions also does not support macro syntax (@daily, @weekly), so use the full expression. Scheduled workflows during periods of high load may fire up to 15 minutes late — design your jobs to be tolerant of this drift.


Converting cron to systemd timers

Modern Linux systems increasingly use systemd timers instead of classic crontab. Systemd's OnCalendar format uses different syntax but covers all the same patterns. The Cron to Systemd Timer Converter converts any 5-field cron expression to its equivalent systemd timer unit configuration, including a complete .timer and .service file template.

Cron pitfalls and edge cases

Even experienced developers encounter silent failures with cron. These are the most common pitfalls — each one has cost production systems unnoticed downtime or duplicate job runs.

Timezone surprises

Cron runs in the server's local timezone by default. If your server is in UTC but your business is in New York (UTC-5), "0 9 * * *" fires at 4 AM local time, not 9 AM. Cloud platforms like GitHub Actions and AWS EventBridge always run in UTC, which means all timezone math falls on you. Always confirm the timezone before deploying a schedule. The Interactive Cron Scheduler lets you simulate runs with timezone offset applied.

Month-end edge cases

Scheduling a job on the 29th, 30th, or 31st of the month causes it to silently skip months that do not have that date. "0 0 31 * *" never runs in April, June, September, or November. "0 0 29 2 *" runs in February only on leap years. If you need a "last day of the month" schedule, you need a smarter approach — either run daily with a script that checks the date, or use a cloud scheduler that supports L (last) day syntax.

DST transitions

Daylight saving time transitions can cause cron jobs to run twice or be skipped. When clocks spring forward, times in the skipped hour never occur. When clocks fall back, times in the repeated hour occur twice. Jobs scheduled in a local timezone during the transition window are affected. The safest practice is to run servers and schedulers in UTC, which never has DST transitions.

Warning

Never rely on cron for exactly-once, time-critical execution. Cron daemons can miss a run if the system is down, rebooting, under heavy load, or if the clock is adjusted. For financial transactions, idempotent job design and a job queue with dead-letter handling are more reliable than raw cron scheduling.

The every-second problem

Standard 5-field cron has a minimum resolution of one minute. If you need a job to run every 10 seconds, cron is not the right tool — use a system timer, a job queue with delays, or the seconds field available in Spring Scheduler and Quartz. Trying to approximate sub-minute schedules with multiple crontab entries is error-prone and creates race conditions when jobs overlap.

Key takeaways

  • A cron expression has five fields: minute (0–59), hour (0–23), day-of-month (1–31), month (1–12), day-of-week (0–7).
  • The six special characters are * (wildcard), , (list), - (range), / (step), ? (no-spec, Quartz only), and @ (macros like @daily).
  • When both day-of-month and day-of-week are non-wildcard, most cron daemons fire if EITHER matches — a common source of unexpected double-runs.
  • Use the Crontab Expression Builder to build visually, the Cron Expression Validator to check syntax, and the Interactive Cron Scheduler to simulate 12 months of runs.
  • GitHub Actions uses 5-field UTC-only cron with no macro support; AWS EventBridge and Google Cloud Scheduler also use UTC; Linux crontab uses the system local timezone.
  • Do not schedule on the 29th, 30th, or 31st if you need the job to run every month — those days do not exist in every month.
  • Standard cron has a one-minute minimum resolution; use systemd timers, job queues, or Spring/Quartz for sub-minute scheduling needs.

Frequently Asked Questions

A cron resolver is a tool that parses a cron expression and translates it into a human-readable schedule description and a list of the next scheduled run times. Given an expression like "0 9 * * 1-5", a resolver tells you "At 09:00 AM, Monday through Friday" and shows you the next five dates and times the job will fire. The Quasar Tools Cron to Human-Readable Translator and Interactive Cron Scheduler both perform this resolution instantly in your browser without uploading anything to a server.

The five fields are minute (0–59), hour (0–23), day of month (1–31), month (1–12), and day of week (0–7, where both 0 and 7 represent Sunday). They run left to right in that order. The expression "30 8 * * 1" means "At 8:30 AM, every Monday." An asterisk (*) in any field means "every valid value for that field." Most standard crontab implementations use exactly these five fields; some extended formats (Spring Scheduler, Quartz) add a sixth seconds field at the start.

An asterisk (*) is the wildcard character in cron — it means "match every valid value for this field." In the minute field, * means every minute (0–59). In the hour field, * means every hour (0–23). In the day-of-week field, * means every day. So "* * * * *" runs every minute of every hour every day. It is the broadest possible value for any field. Use it when a field should not restrict the schedule rather than listing every value explicitly.

Range syntax specifies a span of consecutive values: "1-5" in the day-of-week field means Monday through Friday. Step syntax uses a forward slash to specify an interval: "*/15" in the minute field means every 15 minutes (0, 15, 30, 45). They can be combined: "0-30/10" means every 10 minutes from minute 0 to minute 30 (0, 10, 20, 30). Step syntax is commonly used to run jobs at regular intervals without listing every value explicitly.

Use the step syntax in the minute field: "*/5 * * * *". This expression fires at minutes 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, and 55 of every hour, every day. If you need to run every 5 minutes but only during business hours (9 AM to 5 PM, Monday to Friday), use "*/5 9-17 * * 1-5". Validate the expression in the Cron Expression Validator and preview the exact fire times in the Interactive Cron Scheduler before deploying.

Cron macros are shorthand aliases for common schedule expressions. The most widely supported are @reboot (run once at startup), @yearly or @annually ("0 0 1 1 *"), @monthly ("0 0 1 * *"), @weekly ("0 0 * * 0"), @daily or @midnight ("0 0 * * *"), and @hourly ("0 * * * *"). Support varies by scheduler — Linux crontab and most Unix cron daemons support all six; AWS EventBridge, Google Cloud Scheduler, and GitHub Actions do not support macro syntax. The Cron to Human-Readable Translator handles macros and expands them to their equivalent expressions.

The most common causes are timezone mismatch (cron runs in the server's local timezone, often UTC), off-by-one in day-of-week numbering (0 and 7 both mean Sunday on most systems, but not all), and the interaction between day-of-month and day-of-week fields (when both are non-wildcard, most cron implementations fire if EITHER condition is true, not both). Use the Interactive Cron Scheduler to simulate the exact fire times in UTC versus your expected timezone before concluding there is a bug.

Yes. GitHub Actions supports cron scheduling via the `schedule` trigger with a `cron:` key using standard 5-field cron syntax. GitHub Actions runs on UTC, so adjust your expression accordingly. Note that GitHub Actions does not support cron macros (@daily, @weekly, etc.) — use the full 5-field expression instead. Also, scheduled workflows may not run at exactly the specified time during periods of high load; expect up to 15 minutes of drift. The Crontab Expression Builder generates GitHub Actions-compatible expressions with next run time previews.

ShareXLinkedIn

Related articles