Understanding Cron Expressions: A Practical Guide with Examples

CodeKit
cronschedulingdevops

What Are Cron Expressions?

Cron expressions are strings that define schedules for recurring tasks. Named after the Greek word β€œchronos” (time), they originated in Unix systems as a way to run commands at specified intervals. Today, cron-style scheduling is used everywhereβ€”from Linux crontabs and Kubernetes CronJobs to cloud services like AWS EventBridge and GitHub Actions.

A cron expression tells a scheduler when to run a job, not what to run. Mastering cron syntax means you can precisely control when your backups happen, when reports are generated, or when your CI pipeline triggers.

You can parse and debug cron expressions interactively with the Cron Parser on CodeKit.

The Five-Field Format

The standard cron expression consists of five fields separated by spaces:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ minute (0–59)
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ hour (0–23)
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ day of month (1–31)
β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ month (1–12)
β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ day of week (0–6, where 0 = Sunday)
β”‚ β”‚ β”‚ β”‚ β”‚
* * * * *

Each field specifies when the job should run in that time unit. An asterisk (*) means β€œevery possible value” for that field.

Field-by-Field Breakdown

FieldAllowed ValuesDescription
Minute0–59Which minute of the hour
Hour0–23Which hour of the day
Day of month1–31Which day of the month
Month1–12Which month of the year
Day of week0–6Which day of the week (0 = Sunday)

Some implementations also support a sixth field for seconds (0–59) at the beginning, and a few support year as a seventh field. But the five-field format is the universal baseline.

Special Characters

Cron expressions become powerful through their special characters, which let you express complex schedules compactly.

Asterisk (*) β€” Every Value

The wildcard matches all valid values for the field:

* * * * *    β†’ Every minute of every hour of every day

Comma (,) β€” List of Values

Separate individual values with commas to match specific points:

0 9,12,18 * * *    β†’ At minute 0 of hours 9, 12, and 18 (9 AM, noon, 6 PM)

Hyphen (-) β€” Range

Define a contiguous range of values:

0 9-17 * * *    β†’ At minute 0 of every hour from 9 AM to 5 PM

Ranges and lists can be combined:

0 9-12,14-17 * * *    β†’ At 9–12 AM and 2–5 PM

Slash (/) β€” Step Values

The slash defines a step interval within a range. The number before the slash is the starting point; the number after is the interval:

*/15 * * * *     β†’ Every 15 minutes (at 0, 15, 30, 45)
0 */2 * * *      β†’ Every 2 hours (at 0:00, 2:00, 4:00, ...)
0 9 */3 * *      β†’ Every 3 days at 9 AM

You can combine a starting value with a step:

30 9/2 * * *     β†’ Starting at 9:30 AM, then every 2 hours (9:30, 11:30, 13:30, ...)

Combined Examples

0,30 9-17 * * 1-5    β†’ Every 30 minutes during business hours on weekdays
0 0 1 */3 *          β†’ At midnight on the first day of every quarter

Common Cron Patterns

Here are the schedules you’ll use most often:

ExpressionSchedule
* * * * *Every minute
*/5 * * * *Every 5 minutes
*/15 * * * *Every 15 minutes
0 * * * *Every hour (at minute 0)
0 */2 * * *Every 2 hours
0 9 * * *Every day at 9 AM
0 9 * * 1Every Monday at 9 AM
0 9 * * 1-5Every weekday at 9 AM
0 0 1 * *First day of every month at midnight
0 0 1 1 *January 1st at midnight (yearly)
0 6 * * 1-56 AM every weekday
30 4 * * 04:30 AM every Sunday

Special Strings (Shortcuts)

Many cron implementations support human-readable shortcuts:

ShortcutExpressionMeaning
@yearly0 0 1 1 *Once a year (Jan 1)
@annually0 0 1 1 *Same as @yearly
@monthly0 0 1 * *Once a month
@weekly0 0 * * 0Once a week (Sunday)
@daily0 0 * * *Once a day (midnight)
@midnight0 0 * * *Same as @daily
@hourly0 * * * *Once an hour

These shortcuts are supported by Vixie cron (the default on most Linux distributions), Spring, and many cloud schedulers. They are not part of the POSIX standard.

Platform Differences

Cron syntax varies across platforms. Being aware of these differences prevents subtle scheduling bugs.

Standard Linux (Vixie Cron)

  • Five fields
  • Day of week: 0–6 (0 and 7 both mean Sunday)
  • Supports @reboot to run once after system startup
  • Supports environment variable assignments before the expression

Spring / Quartz Scheduler

  • Six or seven fields (adds seconds; optionally adds year)
  • Day of week: 1–7 (1 = Sunday) or MON–SUN
  • Supports L for β€œlast” (e.g., L in day-of-month means the last day of the month)
  • Supports W for β€œnearest weekday” and # for β€œnth day of the month” (e.g., 6#3 means the third Friday)

AWS EventBridge

  • Six fields (adds year)
  • Supports L, W, and # like Quartz
  • Uses ? as a β€œno specific value” placeholder for day-of-month or day-of-week when one must be unspecified

GitHub Actions

  • Uses a cron-like syntax with five fields
  • Minimum interval is 5 minutes (shorter intervals are ignored)
  • Runs on the default branch only
  • Day of week: 0–6 (0 = Sunday)

Kubernetes CronJobs

  • Standard five-field format
  • Supports @reboot and other shortcuts depending on the underlying cron implementation
  • The startingDeadlineSeconds field controls how late a missed job can still start

Debugging Cron Expressions

Cron bugs are notoriously hard to catch because they only manifest at specific times. Here are strategies to avoid and diagnose them.

1. Calculate Next Run Times

Always verify what your expression actually means by computing the next several execution times. A typo in one field can shift the schedule dramatically.

Use the Cron Parser to enter an expression and see the next N execution times instantly.

2. Watch Out for Day-of-Month and Day-of-Week Interaction

In standard cron, when both day-of-month and day-of-week are specified (neither is *), the job runs when either condition is met (OR logic, not AND). This is a common source of confusion:

0 0 13 * 5    β†’ Runs on the 13th of every month AND every Friday (not just Fridays that fall on the 13th)

Some platforms (like AWS EventBridge) use ? to explicitly mark β€œno specific value” and avoid this ambiguity.

3. Timezone Matters

Cron expressions are evaluated in the timezone of the system running them. A job scheduled for 0 9 * * * runs at 9 AM local server time. If your server is in UTC but your team is in New York, 9 AM UTC is 5 AM Eastern.

Always document the expected timezone, and prefer UTC for server-side schedules to avoid daylight saving time surprises.

4. Daylight Saving Time Edge Cases

When clocks spring forward or fall back, scheduled jobs can be skipped or run twice. For example, 0 2 * * * in a timezone that springs forward from 2:00 AM to 3:00 AM will skip that execution. Conversely, falling back means the job runs twice.

Scheduling outside the 1:00–3:00 AM window avoids most DST issues.

5. Test with Dry Runs

Before deploying a cron job to production, log what it would do without actually doing it. This is especially important for destructive operations like database cleanup or file deletion.

Best Practices

  • Use UTC: Schedule in UTC and convert for display. This eliminates timezone confusion.
  • Add jitter: If multiple jobs share the same schedule, stagger them slightly (e.g., 1,16,31,46 * * * * instead of */15 * * * *) to avoid thundering herd problems.
  • Set a timeout: Always configure a maximum runtime. A job that hangs can accumulate and cause resource exhaustion.
  • Log execution times: Record when each job starts and finishes. This data is invaluable for debugging missed or overlapping runs.
  • Prefer simple expressions: 0 */6 * * * (every 6 hours) is easier to verify than 0 0,6,12,18 * * *, even though they’re equivalent.

Conclusion

Cron expressions are a compact, powerful way to define recurring schedules. The five-field format covers most needs, and the special characters (*, ,, -, /) let you express everything from β€œevery minute” to β€œthe third Friday of every other month.” The key to using cron reliably is understanding platform differences, being aware of timezone and DST edge cases, and always verifying your expressions before deploying them.

To quickly validate and visualize any cron expression, try the Cron Parser on CodeKitβ€”it shows you the next execution times, field breakdowns, and a human-readable description of your schedule.