Cron Expressions Explained:
Complete Guide with Examples

Cron expressions are the lingua franca of scheduled tasks. Whether you're writing a Linux crontab, a GitHub Actions workflow, a Kubernetes CronJob, or an AWS EventBridge rule — you're writing cron. This guide covers everything from the basics to edge cases, with 20+ real examples.

⚙ Try it interactively

Use the Cron Expression Parser & Generator to parse any expression to plain English, preview next run times with timezone support, and build expressions visually — no syntax memorization required.

What is Cron?

Cron is a Unix-based job scheduler that has been running on Linux and macOS systems since the 1970s. The name comes from the Greek word for time, chronos. A background daemon (called the cron daemon or crond) reads a configuration file called a crontab (cron table) and executes commands at the times specified in it.

Today, cron syntax has spread far beyond Unix systems. It's the standard format for scheduled tasks in cloud platforms, CI/CD tools, and application frameworks. The key insight: once you understand cron expressions, you can write schedules for almost any modern system.

The 5-Field Cron Format

A standard cron expression has five fields, separated by spaces:

┌─────────── minute (0–59)
│ ┌───────── hour (0–23)
│ │ ┌─────── day of month (1–31)
│ │ │ ┌───── month (1–12 or JAN–DEC)
│ │ │ │ ┌─── day of week (0–7, 0=Sun, 7=Sun, or SUN–SAT)
│ │ │ │ │
* * * * *

An asterisk (*) in any field means "every possible value." So * * * * * runs every minute of every hour of every day.

Field Reference

FieldValuesSpecial
Minute0–59*, ,, -, /
Hour0–23 (0 = midnight)*, ,, -, /
Day of month1–31*, ,, -, /, ?, L, W
Month1–12 or JAN–DEC*, ,, -, /
Day of week0–7 (0=Sun, 7=Sun) or SUN–SAT*, ,, -, /, ?, L, #

Special Characters

Asterisk (*) — Every Value

The asterisk matches every valid value for a field. * * * * * runs every minute. 0 * * * * runs at minute 0 of every hour (i.e., every hour on the hour).

Comma (,) — List of Values

Commas let you specify multiple values. 0,15,30,45 * * * * runs at :00, :15, :30, and :45 of every hour. 0 0 * * 1,3,5 runs at midnight on Monday, Wednesday, and Friday.

Dash (-) — Range

Dashes specify ranges. 0 9 * * 1-5 runs at 9:00 AM Monday through Friday. 0 8-18 * * * runs every hour from 8 AM to 6 PM.

Slash (/) — Step Values

The slash character defines steps (increments). */15 * * * * means "every 15 minutes" (runs at :00, :15, :30, :45). 0 */2 * * * means "every 2 hours on the hour." You can also use 1/2 to mean "starting at 1, every 2 steps."

Question Mark (?) — No Specific Value

Used in some systems (Quartz, AWS EventBridge) for day-of-month or day-of-week to mean "I don't care." Required when you specify one of day-of-month/day-of-week but not the other. Not supported in standard Unix crontab.

L — Last

When used in day-of-month, L means the last day of the month. 0 0 L * * runs at midnight on the last day of every month. When used in day-of-week (e.g., 5L), means the last Friday of the month. Supported by Quartz and some cloud schedulers, not Unix crontab.

# — Nth Weekday

Used as weekday#n to mean the nth occurrence of a weekday in the month. 0 0 * * 2#1 means "midnight on the first Monday of the month." Quartz Scheduler and AWS EventBridge support this; standard crontab does not.

20 Real Cron Expression Examples

ExpressionMeaning
* * * * *Every minute
*/5 * * * *Every 5 minutes
*/15 * * * *Every 15 minutes
0 * * * *Every hour, on the hour
0 */2 * * *Every 2 hours, on the hour
0 8-18 * * 1-5Every hour from 8 AM to 6 PM, weekdays only
0 0 * * *Every day at midnight (00:00)
0 12 * * *Every day at noon (12:00 PM)
30 9 * * 1-5Every weekday at 9:30 AM
0 0 * * 1Every Monday at midnight
0 0 * * 0Every Sunday at midnight
0 0 * * 0,6Every Saturday and Sunday at midnight
0 0 1 * *Midnight on the 1st of every month
0 0 15 * *Midnight on the 15th of every month
0 0 L * *Midnight on the last day of every month
0 0 1 */3 *Midnight on the 1st of every 3rd month (quarterly)
0 0 1 1 *Midnight on January 1st (yearly)
0 8 * * 2#18 AM on the first Tuesday of every month
0 9,12,17 * * 1-59 AM, 12 PM, and 5 PM on weekdays
*/30 9-17 * * 1-5Every 30 minutes during business hours (9–5, weekdays)

The 6-Field Format (With Seconds)

Some platforms add a seconds field at the beginning, creating a 6-field expression:

┌──────────── second (0–59)
│ ┌─────────── minute (0–59)
│ │ ┌───────── hour (0–23)
│ │ │ ┌─────── day of month (1–31)
│ │ │ │ ┌───── month (1–12)
│ │ │ │ │ ┌─── day of week (0–7)
│ │ │ │ │ │
* * * * * *

6-field examples:

⚠ Don't Mix Formats

A 6-field expression will be rejected by platforms expecting 5 fields, and vice versa. Always check your platform's documentation. The Cron Parser on this page has a "6-field" toggle to switch between modes.

Timezone Handling

Cron expressions have no built-in timezone information — they're always interpreted relative to a specific timezone. This causes problems when your cron jobs run on servers with different timezone configurations.

Key rules:

⚠ Daylight Saving Time (DST) Caveat

When DST transitions happen, cron jobs may run twice (when clocks fall back) or not at all (when clocks spring forward). If you have a job at 2:30 AM in a DST timezone, test it around transition dates. Using UTC for server-side cron avoids this issue entirely.

Platform Differences At a Glance

PlatformFieldsSecondsL, W, #Default TZ
Unix crontab5NoNoSystem
GitHub Actions5NoNoUTC
GCP Cloud Scheduler5NoNoConfigurable
Kubernetes CronJob5NoNoNode TZ (often UTC)
Quartz Scheduler6 (sec first)YesYesJVM default
Spring Boot @Scheduled6 (sec first)YesPartialJVM default
AWS EventBridge6 (sec first)*No*YesUTC / Configurable

* AWS EventBridge uses a 6-field format but the seconds field is always 0. The ? character is required in either day-of-month or day-of-week when the other is specified.

Common Mistakes

1. Day-of-week numbering

Both 0 and 7 represent Sunday in standard cron, but some platforms only accept 0–6. SUN works in most implementations. When in doubt, use 0 for Sunday.

2. "Every minute" vs "Every hour"

* * * * * runs every minute (60 times per hour). If you mean "once per hour," use 0 * * * *. A very common mistake is writing 0 8 * * * thinking it runs every 8 hours, when it actually means "at 8:00 AM every day."

3. Step values don't divide evenly

*/7 * * * * runs at :00, :07, :14, :21, :28, :35, :42, :49, :56 — 9 times per hour, unevenly. Use */5, */10, */15, */20, or */30 for clean divisions.

4. Month names are case-sensitive in some systems

Use uppercase for month and day names: JAN, MON, not jan or mon. Or just use numbers to be safe.

5. Confusing UTC with local time

If your server is in UTC and you want a job at 9 AM New York time (UTC-5 in winter), you need 0 14 * * * (14:00 UTC = 9:00 AM EST). Always verify with a tool that shows next run times in your target timezone.

⚙ Parse & Build Cron Expressions

Use the free Cron Expression Parser to get instant plain-English descriptions, preview next 10 run times in any timezone, and build expressions with the visual editor.

Open Cron Parser →

Cron Best Practices

Frequently Asked Questions

What does '*/15 * * * *' mean?

It runs every 15 minutes. The */15 in the minute field means "every 15 minutes starting from 0," so it runs at :00, :15, :30, and :45 past every hour.

How do I run a job at 9:30 AM every weekday?

Use 30 9 * * 1-5. The minute field is 30, hour is 9, day-of-month and month are *, and day-of-week is 1-5 (Monday through Friday).

What's the difference between '0 0 1 * *' and '0 0 * * 1'?

0 0 1 * * runs at midnight on the 1st of every month. 0 0 * * 1 runs at midnight every Monday. Both run once, but on different schedules.

Can I run a job every 10 seconds?

Not with standard Unix crontab — the minimum resolution is 1 minute. With 6-field cron (Quartz, Spring Boot), you can use */10 * * * * * for every 10 seconds. For sub-minute scheduling in Unix, use a loop inside a shell script or a proper job queue.

Why does my cron job not run on the expected day?

Double-check the timezone. If your server is UTC and you're in EST (UTC-5), a job set for 9 AM needs to be 0 14 * * * in UTC. Also verify that day-of-week numbering is correct — 1 is Monday, not Sunday.