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.
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
| Field | Values | Special |
|---|---|---|
| Minute | 0–59 | *, ,, -, / |
| Hour | 0–23 (0 = midnight) | *, ,, -, / |
| Day of month | 1–31 | *, ,, -, /, ?, L, W |
| Month | 1–12 or JAN–DEC | *, ,, -, / |
| Day of week | 0–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
| Expression | Meaning |
|---|---|
* * * * * | 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-5 | Every 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-5 | Every weekday at 9:30 AM |
0 0 * * 1 | Every Monday at midnight |
0 0 * * 0 | Every Sunday at midnight |
0 0 * * 0,6 | Every 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#1 | 8 AM on the first Tuesday of every month |
0 9,12,17 * * 1-5 | 9 AM, 12 PM, and 5 PM on weekdays |
*/30 9-17 * * 1-5 | Every 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:
*/30 * * * * *— Every 30 seconds0 */5 * * * *— Every 5 minutes (on the minute)0 0 9 * * 1-5— Every weekday at 9:00:00 AM0 0 0 1 * *— Midnight on the 1st of every month
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:
- Linux crontab uses the system timezone. Most cloud VMs default to UTC. Set
CRON_TZ=America/New_Yorkat the top of your crontab to override. - GitHub Actions cron always runs in UTC.
0 9 * * *means 9:00 AM UTC, which is 5:00 AM Eastern in winter or 4:00 AM in summer. - AWS EventBridge supports cron in UTC by default. You can specify a schedule timezone in the rule settings.
- GCP Cloud Scheduler lets you set the timezone per job.
- Kubernetes CronJobs use the timezone of the node running the controller. Often UTC in cloud clusters.
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
| Platform | Fields | Seconds | L, W, # | Default TZ |
|---|---|---|---|---|
| Unix crontab | 5 | No | No | System |
| GitHub Actions | 5 | No | No | UTC |
| GCP Cloud Scheduler | 5 | No | No | Configurable |
| Kubernetes CronJob | 5 | No | No | Node TZ (often UTC) |
| Quartz Scheduler | 6 (sec first) | Yes | Yes | JVM default |
| Spring Boot @Scheduled | 6 (sec first) | Yes | Partial | JVM default |
| AWS EventBridge | 6 (sec first)* | No* | Yes | UTC / 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
- Use UTC for server cron — it avoids DST surprises and makes logs predictable.
- Stagger jobs — if you have 10 jobs that all run at midnight, offset them by a few minutes to avoid resource spikes.
- Test edge cases — verify behavior at month boundaries, DST transitions, and leap year end-of-February.
- Monitor job duration — if a job takes longer than its interval, two instances can overlap. Use file locks or job managers like Celery or Sidekiq for overlapping protection.
- Log every run — redirect cron output to a log file:
0 * * * * /path/to/job.sh >> /var/log/job.log 2>&1 - Use
@rebootfor startup tasks — on Linux crontab,@reboot commandruns once when the system boots up.
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.