Skip to main content
Dev Utilities Pro

Scheduling

Cron Expression Syntax — A Developer's Field Guide

Updated May 23, 2026 · By Byron Malone

A cron expression is a five-field string that schedules recurring tasks on Unix systems. 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 0 and 7 both mean Sunday). Every platform — Linux, AWS EventBridge, GitHub Actions, Quartz for Java — uses a slightly different dialect. The critical rules: always write cron in UTC for production systems; never rely on timezone abbreviations like EST; use ? in AWS EventBridge where POSIX uses *; and verify your expression against a next-execution calculator before deploying. Primary source: IEEE Std 1003.1 (POSIX crontab specification).

What cron is and where it runs

Cron is a time-based job scheduler built into Unix-like operating systems. The cron daemon (crond on Red Hat/CentOS; cron on Debian/Ubuntu) reads a per-user configuration file called a crontab (cron table) and executes the specified commands at the specified times. The crontab format was standardized in IEEE Std 1003.1 (POSIX.1-2017), the portable operating system standard that defines the interface between software and Unix-compatible systems.

Cron expressions appear in a wide range of contexts beyond the Unix crontab: Kubernetes CronJob manifests (using POSIX five-field syntax), AWS EventBridge scheduled rules (using a six-field variant with a year field), GitHub Actions workflow triggers (using POSIX five-field syntax, UTC only), and Java/Spring scheduling via the Quartz scheduler library (using a six-field variant with a seconds field). Understanding the differences between these dialects is the most common source of scheduling bugs when moving between environments.

Advertisement

The five POSIX fields: syntax and valid ranges

A POSIX cron entry has exactly five fields followed by the command to execute. Fields are separated by whitespace:

┌─────────────── minute (0–59)
│ ┌───────────── hour (0–23)
│ │ ┌─────────── day-of-month (1–31)
│ │ │ ┌───────── month (1–12, or jan–dec)
│ │ │ │ ┌─────── day-of-week (0–7, 0 and 7 = Sunday)
│ │ │ │ │
* * * * *  command-to-run

Special characters valid in any field:

  • * — wildcard: matches every valid value in the field.* * * * * runs every minute.
  • */N — step: every N units.*/15 * * * * runs at :00, :15, :30, :45 each hour.
  • N-M — range: every value from N to M inclusive.0 9-17 * * 1-5 runs at minute 0 of every hour from 9am to 5pm, Monday through Friday.
  • N,M,P — list: exactly these values.0 0 1,15 * * runs at midnight on the 1st and 15th of each month.
  • N-M/S — range with step.0 8-18/2 * * * runs at minute 0 of hours 8, 10, 12, 14, 16, 18.

Common expressions with plain-English translation:

0 * * * *      → Every hour at minute 0
0 0 * * *      → Daily at midnight
0 9 * * 1-5   → Weekdays at 9:00 AM
*/5 * * * *    → Every 5 minutes
0 0 1 * *      → First of every month at midnight
0 0 * * 0      → Every Sunday at midnight
30 6 * * 1     → Every Monday at 6:30 AM

Platform dialect differences: the four traps

The four dialects that matter in 2026 — POSIX/Linux, Quartz (Java), AWS EventBridge, and GitHub Actions — differ in four ways that consistently cause bugs when migrating expressions between environments.

Trap 1: AWS EventBridge requires ? in dom or dow. In POSIX cron, you can specify both day-of-month and day-of-week with * — the daemon fires when either matches. AWS EventBridge prohibits this: you must use ? (unspecified) in exactly one of dom or dow. The valid EventBridge form for “noon every day” is 0 12 * * ? * (with the year field at the end). The POSIX form 0 12 * * * is invalid in EventBridge and will fail silently or produce a validation error depending on how the rule is created.

Trap 2: Quartz day-of-week numbering starts at 1 = Sunday. POSIX cron uses 0 = Sunday through 6 = Saturday (with 7 also meaning Sunday). Quartz uses 1 = Sunday through 7 = Saturday. An expression with 5 in the day-of-week field means Thursday in Quartz but Friday in POSIX. AWS EventBridge also uses 1 = Sunday convention. Use named abbreviations (SUN, MON, TUE, WED, THU, FRI, SAT) to avoid this class of bugs — they are unambiguous across all dialects that support them.

Trap 3: GitHub Actions always runs in UTC. There is no timezone configuration for GitHub Actions cron schedules. If your team is in EST (UTC−5) and you want a job at 9am ET, the expression is 0 14 * * * in winter and 0 13 * * * in summer (EDT, UTC−4). This is frequently missed — the workflow silently shifts by an hour twice a year.

Trap 4: Quartz adds a seconds field at position 0. A Quartz cron expression has six fields: second minute hour dom month dow. A POSIX expression pasted into a Quartz scheduler is shifted one field to the right — what was intended as a minute becomes the second field, and the expression fires at the wrong time or fails validation. The Quartz equivalent of the POSIX 0 12 * * * is 0 0 12 * * ?.

Advertisement

Timezone handling: always schedule in UTC

The standard production pattern for cron scheduling is: express all times in UTC, document the local-time equivalent in a comment, and configure all cron servers to run in UTC (via CRON_TZ=UTC at the top of the crontab file or TZ=UTC in the server environment). This avoids the two DST transition problems:

  • Spring-forward skip: In US timezones, clocks jump from 2:00am to 3:00am on the second Sunday in March. A cron expression set to 0 2 * * * in a DST-observing timezone will not fire on that night — the 2am window does not exist. If that job exports daily reports, you'll have a missing report the morning after DST begins.
  • Fall-back duplicate: In November, clocks repeat the 1:00am–2:00am hour. An expression set to 30 1 * * * will fire twice — once at 1:30am standard time and again when the clocks fall back. If that job charges customers or sends emails, you have a billing or spam incident.

UTC has no DST transitions. A cron job scheduled to 0 14 * * 1-5 UTC fires at exactly the same moment every weekday, year-round, regardless of the season or the timezone policy of the host server.

Linux crontab supports a per-crontab timezone override via the CRON_TZ environment variable (added to the top of the file before any entries). This accepts IANA timezone names: CRON_TZ=America/Chicago. AWS EventBridge Scheduler (not EventBridge Rules) adds a separate timezone parameter. GitHub Actions has no timezone support — UTC only.

Common scheduling patterns

Practical patterns for the most common scheduling requirements, with dialect notes where they differ:

# Every 5 minutes between 9am and 5pm UTC, weekdays
# POSIX: */5 9-17 * * 1-5
# Quartz: 0 */5 9-17 * * MON-FRI
# EventBridge: */5 9-17 ? * MON-FRI *

# First day of every month at midnight UTC
# POSIX: 0 0 1 * *
# Quartz: 0 0 0 1 * ?
# EventBridge: 0 0 1 * ? *

# Last day of month at 11pm UTC (Quartz only, others use script workaround)
# Quartz: 0 0 23 L * ?

# Every Sunday at 2am UTC
# POSIX: 0 2 * * 0    (or 0 2 * * SUN)
# Quartz: 0 0 2 ? * SUN
# EventBridge: 0 2 ? * SUN *

# At 6:30am, 12:30pm, 6:30pm UTC
# POSIX: 30 6,12,18 * * *
# Quartz: 0 30 6,12,18 * * ?

Pre-deployment validation checklist

Before deploying any cron expression to production, verify the following:

  1. Run the expression through a next-execution calculator and confirm the five next fire times are what you expect.
  2. Check the expression in the specific dialect of your deployment target (POSIX/Quartz/EventBridge/GitHub Actions) — not a generic validator.
  3. Verify that the expression fires on months with 28, 29, 30, and 31 days if day-of-month is specified.
  4. For expressions in the 1:00am–3:00am window in DST-observing timezones: confirm behavior during spring-forward and fall-back transitions, or move the expression to UTC.
  5. Confirm the day-of-week numbering convention matches your target platform (POSIX 0 = Sunday vs. Quartz 1 = Sunday).
  6. For AWS EventBridge: confirm exactly one of dom or dow uses ?.
  7. If using special characters (L, W, #): confirm your platform supports them.
Advertisement

Build and validate your expression

Use the Dev Utilities Pro Cron Expression Builder to validate your expression, see it translated to plain English, and compute the next 5 execution times — in your selected IANA timezone, across all four dialects.

Open cron expression builder

By Last updated

Founder, Bedrocka Tools

Primary source: IEEE Std 1003.1 (POSIX.1-2017) — crontab specification. See the full cron syntax methodology for algorithm documentation and platform comparison table.