Cron Schedule Examples Explained
- Cron Schedule Examples Explained
- What Is Cron?
- The Five-Field Cron Expression
- Field Ranges at a Glance
- Special Characters
- — Wildcard (every)
- , — List (multiple values)
- - — Range
- / — Step
- ? — No specific value (Quartz / Spring only)
- Named Shortcuts
- 25+ Cron Schedule Examples
- Every-Interval Schedules
- Daily Schedules
- Weekly and Weekday Schedules
- Monthly and Yearly Schedules
- The Day-of-Month vs Day-of-Week OR Gotcha
- Why Does This Happen?
- How to Work Around It
- Crontab: run every 15th regardless of day
- wrapper.sh: check if today is Monday
- Common Cron Mistakes
- 1. Timezone Confusion
- 2. Overlapping Runs
- 3. Cron Runs in a Minimal Environment
- 4. Output Goes to /dev/null or Generates Email Spam
- Discard all output
- Log to a file
- Log with timestamps
- 5. The No-Seconds Field Mistake
- WRONG for Unix cron — this is interpreted as:
- minute=0, hour=6, day=, month=, day-of-week= with 'command' as extra token
- 6. Assuming a Job Runs Exactly On Schedule
- 7. Forgetting to Handle Failures
- Where Cron Runs
- User Crontabs
- System-Wide Crontab: /etc/crontab
- /etc/crontab
- Drop-In Directories: /etc/cron.d
- apt certbot logrotate php8.2 postfix
- Convenience Directories
- Cron in Cloud and Container Environments
- AWS EventBridge Scheduler
- GCP Cloud Scheduler
- Kubernetes CronJob
- GitHub Actions
- Debugging Cron Jobs
- 1. Test the Command Manually First
- 2. Simulate the Cron Environment
- 3. Check Cron Logs
- systemd-based systems (most modern Linux distros)
- Or with grep for your specific job
- Older systems
- 4. Log Output from the Script
- 5. Verify the Crontab Syntax
- Cron Alternatives
- Quick Reference Card
- Cron expression format:
- MIN HOUR DOM MON DOW COMMAND
- Special characters:
- every valid value
- , list: 1,3,5
- - range: 1-5
- / step: /15 (every 15)
- Examples:
- Conclusion
Cron Schedule Examples Explained
Cron is one of the most enduring pieces of Unix infrastructure. It has been scheduling tasks reliably since 1975 — predating the web, Linux, and most modern programming languages. If you run anything on a Linux or macOS server, you almost certainly use cron or a system that borrowed its syntax.
This guide explains the cron expression format from scratch, gives you 25+ copy-paste schedule examples grouped by use case, and covers the gotchas that cause real production incidents.
If you want to build and validate cron expressions interactively, the Cron Expression Builder lets you click fields and instantly see the next run times.
What Is Cron?
Cron is a time-based job scheduler built into Unix-like operating systems. A background process called the cron daemon (crond) wakes up every minute, reads a set of schedule definitions called crontabs, and runs any commands whose schedule matches the current time.
The name comes from Chronos, the Greek god of time.
Cron is ideal for:
- Recurring system maintenance (log rotation, disk cleanup, cache warming)
- Scheduled data pipelines and ETL jobs
- Regular report generation and email dispatch
- Database backups
- Health checks and watchdog scripts
- Periodic API polling
The Five-Field Cron Expression
A standard cron expression has exactly five fields separated by whitespace, followed by the command to run:
* * * * * command to execute
│ │ │ │ │
│ │ │ │ └── Day of week (0–7, where 0 and 7 are both Sunday)
│ │ │ └──── Month (1–12)
│ │ └────── Day of month (1–31)
│ └──────── Hour (0–23)
└────────── Minute (0–59)Important: Cron has NO seconds field. The smallest resolution is one minute. Systems that claim "cron-like" syntax with six fields (common in Spring Boot, Kubernetes CronJobs with some controllers, and cloud schedulers) add a seconds field — but this is a non-standard extension. Always check the documentation of the specific system you are using.
Field Ranges at a Glance
| Field | Position | Range | Notes |
|---|---|---|---|
| Minute | 1st | 0–59 | |
| Hour | 2nd | 0–23 | 24-hour clock |
| Day of month | 3rd | 1–31 | See OR-gotcha below |
| Month | 4th | 1–12 | Also accepts JAN–DEC |
| Day of week | 5th | 0–7 | 0 and 7 = Sunday; also accepts SUN–SAT |
Special Characters
Five special characters control how each field is interpreted:
`*` — Wildcard (every)
Matches every valid value for that field.
* * * * * ← runs every minute of every hour of every day`,` — List (multiple values)
Specifies a list of values.
0 9,17 * * * ← runs at 09:00 and 17:00 every day`-` — Range
Specifies a contiguous range of values.
0 9-17 * * * ← runs at 09:00, 10:00, 11:00, ... 17:00 every day`/` — Step
Specifies a step interval. */5 means "every 5".
*/5 * * * * ← runs every 5 minutes
0 */4 * * * ← runs every 4 hours, on the hourYou can combine step with a range: 10-50/10 means "10, 20, 30, 40, 50".
`?` — No specific value (Quartz / Spring only)
The ? character is used in day-of-month or day-of-week fields in non-standard Quartz Scheduler syntax to mean "I am not specifying a value here." Standard Unix cron does not support ? — use * instead.
Named Shortcuts
Many cron implementations support convenience strings in place of the five fields:
| Shortcut | Equivalent | Meaning |
|---|---|---|
@yearly / @annually |
0 0 1 1 * |
Once a year, midnight Jan 1 |
@monthly |
0 0 1 * * |
Once a month, midnight on the 1st |
@weekly |
0 0 * * 0 |
Once a week, midnight Sunday |
@daily / @midnight |
0 0 * * * |
Once a day, midnight |
@hourly |
0 * * * * |
Once an hour, at minute 0 |
@reboot |
— | Run once at startup |
25+ Cron Schedule Examples
Every-Interval Schedules
| Schedule | Expression | Notes |
|---|---|---|
| Every minute | * * * * * |
Rarely useful in production — high overhead |
| Every 2 minutes | */2 * * * * |
|
| Every 5 minutes | */5 * * * * |
Common for health checks |
| Every 10 minutes | */10 * * * * |
|
| Every 15 minutes | */15 * * * * |
|
| Every 30 minutes | */30 * * * * |
Or 0,30 * * * * |
| Every hour | 0 * * * * |
At minute 0 of every hour |
| Every 2 hours | 0 */2 * * * |
|
| Every 4 hours | 0 */4 * * * |
|
| Every 6 hours | 0 */6 * * * |
00:00, 06:00, 12:00, 18:00 |
| Every 12 hours | 0 */12 * * * |
Midnight and noon |
Daily Schedules
| Schedule | Expression | Notes |
|---|---|---|
| Every day at midnight | 0 0 * * * |
Or @daily |
| Every day at 1 AM | 0 1 * * * |
|
| Every day at 6 AM | 0 6 * * * |
Good for morning reports |
| Every day at noon | 0 12 * * * |
|
| Every day at 9:30 AM | 30 9 * * * |
|
| Every day at 11:45 PM | 45 23 * * * |
|
| Twice daily (6 AM and 6 PM) | 0 6,18 * * * |
|
| Three times daily | 0 8,12,18 * * * |
Weekly and Weekday Schedules
| Schedule | Expression | Notes |
|---|---|---|
| Every Sunday at midnight | 0 0 * * 0 |
Or @weekly |
| Every Monday at 8 AM | 0 8 * * 1 |
|
| Every Friday at 5 PM | 0 17 * * 5 |
End-of-week jobs |
| Weekdays at 9 AM | 0 9 * * 1-5 |
Monday through Friday |
| Weekdays at 6 AM and 6 PM | 0 6,18 * * 1-5 |
|
| Weekends only at noon | 0 12 * * 6,0 |
Saturday and Sunday |
Monthly and Yearly Schedules
| Schedule | Expression | Notes |
|---|---|---|
| 1st of every month, midnight | 0 0 1 * * |
Or @monthly |
| 1st and 15th, 6 AM | 0 6 1,15 * * |
Semi-monthly |
| Last business day of month | Not expressible in standard cron | Use a wrapper script |
| Every January 1st, midnight | 0 0 1 1 * |
Or @yearly |
| Every quarter (Jan, Apr, Jul, Oct) | 0 0 1 1,4,7,10 * |
|
| Every 6 months (Jan 1 and Jul 1) | 0 0 1 1,7 * |
The Day-of-Month vs Day-of-Week OR Gotcha
This is the most surprising behavior in standard cron and causes real bugs.
The rule: If both the day-of-month field AND the day-of-week field are restricted (not *), cron treats them as an OR condition, not AND. The job runs when either condition is true.
Most people expect AND behavior — the job should run on the 15th, but only if it's a Monday. Cron does not work that way.
0 9 15 * 1You might read this as: "Run at 9 AM on the 15th of the month, but only if it's a Monday."
What cron actually does: Run at 9 AM on ANY Monday, and ALSO on every 15th of every month regardless of day of week.
Why Does This Happen?
The POSIX specification defines this behavior explicitly. The rationale is that common scheduling needs — "run on every Monday AND every 15th" — would be cumbersome to express otherwise. But the AND interpretation is far more intuitive and this is a frequent source of confusion.
How to Work Around It
If you need the AND behavior ("the 15th, only if it is a Monday"), do not express it in the cron expression. Instead, use a wildcard in the day-of-week field and add a check inside your script:
# Crontab: run every 15th regardless of day
0 9 15 * * /path/to/wrapper.sh
# wrapper.sh: check if today is Monday
#!/bin/bash
[ $(date +%u) -eq 1 ] && /path/to/actual-script.shAlternatively, use a scheduling system that supports compound day logic, such as AWS EventBridge Scheduler or a Kubernetes CronJob with a smarter controller.
Common Cron Mistakes
1. Timezone Confusion
Cron runs in the timezone of the server, which is often UTC in production environments. If your server is UTC and you write:
0 9 * * * # "Run at 9 AM"...it runs at 09:00 UTC. For users in New York (UTC-5 in winter), that is 4 AM. This catches teams off guard when a "morning report" arrives at 4 AM local time.
Solutions:
- Know your server's timezone:
timedatectlon systemd systems,dateto see the current offset. - Set
CRON_TZ(orTZ) at the top of your crontab to specify the timezone explicitly. GNU cron supports this; not all cron implementations do. - Convert your desired local time to UTC and write the UTC time in the crontab.
- Use a cloud scheduler (AWS EventBridge, GCP Cloud Scheduler, Azure Logic Apps) that has first-class timezone support.
2. Overlapping Runs
If your job takes longer than the interval between runs, multiple instances will overlap. A backup job that takes 75 minutes scheduled every hour means two instances run simultaneously for 15 minutes every hour — reading and writing the same data.
Solution: Use a lock file or a tool like flock:
*/30 * * * * flock -n /var/lock/myjob.lock /path/to/myjob.shflock -n exits immediately if the lock is already held, so overlapping runs skip instead of pile up.
3. Cron Runs in a Minimal Environment
Cron jobs do not inherit your interactive shell environment. The PATH is usually /usr/bin:/bin, and none of your shell profile files (.bashrc, .bash_profile, .zshrc) are sourced. This means:
- Commands that work in your terminal may fail with "command not found" in cron.
- Environment variables your app depends on are not set.
nvm,rbenv,pyenv, and similar version managers are not initialized.
Solutions:
- Use full absolute paths:
/usr/local/bin/python3instead ofpython3. - Set the
PATHvariable at the top of your crontab:PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - Source the necessary profile files at the start of your script:
#!/bin/bash source /home/user/.nvm/nvm.sh nvm use 20 node /path/to/app.js - Store secrets in a file that your script reads, not in crontab environment variables (they appear in process listings).
4. Output Goes to /dev/null or Generates Email Spam
By default, cron emails any stdout or stderr output to the local system user. On servers without a working mail system, output is silently discarded. On servers with mail, you get a flood of emails.
Solution: Redirect output explicitly:
# Discard all output
0 6 * * * /path/to/script.sh > /dev/null 2>&1
# Log to a file
0 6 * * * /path/to/script.sh >> /var/log/myjob.log 2>&1
# Log with timestamps
0 6 * * * /path/to/script.sh >> /var/log/myjob.log 2>&1 && echo "$(date): success" >> /var/log/myjob.logOr set MAILTO at the top of the crontab to suppress all emails:
MAILTO=""5. The No-Seconds Field Mistake
Developers moving from Quartz (Java), Spring, or some cloud schedulers to standard cron sometimes add a sixth field for seconds:
# WRONG for Unix cron — this is interpreted as:
# minute=0, hour=6, day=*, month=*, day-of-week=* with 'command' as extra token
0 0 6 * * * /path/to/script.shUnix cron will silently do the wrong thing or throw a parse error. Drop the seconds field.
6. Assuming a Job Runs Exactly On Schedule
Cron does not guarantee sub-minute precision. The daemon wakes up every minute and checks whether anything is due. Under heavy system load, the daemon itself may wake up a few seconds late. Do not write jobs that depend on exact-to-the-second execution.
7. Forgetting to Handle Failures
Cron does not retry failed jobs. If your script exits with a non-zero code at 3 AM, the next run is tomorrow at 3 AM unless you add monitoring. Always:
- Log exit codes.
- Set up alerting for critical jobs (PagerDuty, Slack webhook, etc.).
- Consider tools like
cronitor,healthchecks.io, orDead Man's Snitchthat page you if a job does not check in.
Where Cron Runs
User Crontabs
The standard way to manage per-user cron jobs:
crontab -e # open your crontab in $EDITOR
crontab -l # list your current crontab
crontab -r # remove your entire crontab (CAREFUL)
crontab -u alice -l # view another user's crontab (as root)User crontabs are stored in /var/spool/cron/crontabs/ (location varies by distro). Do not edit these files directly — always use crontab -e to ensure syntax validation.
System-Wide Crontab: /etc/crontab
The system crontab has a slightly different format — it adds a username field before the command:
# /etc/crontab
MINUTE HOUR DOM MONTH DOW USER COMMAND
0 6 * * * root /usr/sbin/logrotate /etc/logrotate.confDrop-In Directories: /etc/cron.d
Packages and applications drop crontab files into /etc/cron.d/. These use the same six-column format as /etc/crontab (with the username field). This is the preferred mechanism for system services because it keeps each application's schedule in its own file.
ls /etc/cron.d/
# apt certbot logrotate php8.2 postfixConvenience Directories
| Directory | Default Schedule |
|---|---|
/etc/cron.hourly/ |
Every hour |
/etc/cron.daily/ |
Every day (usually early morning) |
/etc/cron.weekly/ |
Every week (usually Sunday morning) |
/etc/cron.monthly/ |
First of every month |
Drop an executable script into any of these directories and run-parts (called from /etc/crontab) will run it on schedule. No crontab syntax needed — just make sure the script is executable (chmod +x) and has no extension (some run-parts versions skip files with dots in the name).
Cron in Cloud and Container Environments
AWS EventBridge Scheduler
AWS uses a six-field cron expression with a years field:
cron(0 6 * * ? *) # 6 AM UTC every dayThe ? is required in either day-of-month or day-of-week (the Quartz convention). The years field is optional but must be present. Supports rate expressions as an alternative: rate(1 day).
GCP Cloud Scheduler
Uses standard five-field Unix cron syntax. Supports timezone selection natively — no more UTC mental arithmetic.
0 6 * * * (America/New_York) # 6 AM EasternKubernetes CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-report
spec:
schedule: "0 6 * * *" # Standard 5-field cron
timeZone: "America/New_York" # Kubernetes 1.27+ supports native TZ
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
containers:
- name: reporter
image: myapp:latest
restartPolicy: OnFailureK8s CronJob gotchas:
- If the cron controller misses a schedule (e.g., during a cluster outage), it will catch up according to
startingDeadlineSeconds. Configure this carefully. - Set
concurrencyPolicy: Forbidto prevent overlapping runs (equivalent toflockin Linux cron). - Resource limits on the Job's pod spec are important — runaway jobs have no cron-level timeout.
GitHub Actions
on:
schedule:
- cron: '0 6 * * *' # 6 AM UTC dailyGitHub Actions cron jobs always run in UTC. The minimum interval is every 5 minutes. GitHub notes that workflows may be delayed during high demand periods.
Debugging Cron Jobs
Cron jobs failing silently is a rite of passage. Here is a systematic debugging approach:
1. Test the Command Manually First
Run the exact command from crontab (with the full path) in a terminal. If it fails there, it will fail in cron.
2. Simulate the Cron Environment
env -i HOME=/root LOGNAME=root USER=root \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin \
SHELL=/bin/sh \
/bin/sh -c '/path/to/your/command'This strips your environment variables and tests the script with only what cron provides.
3. Check Cron Logs
# systemd-based systems (most modern Linux distros)
journalctl -u cron -f
# Or with grep for your specific job
journalctl -u cron | grep myjob
# Older systems
tail -f /var/log/cron
tail -f /var/log/syslog | grep cron4. Log Output from the Script
Add logging directly to your crontab line while debugging:
*/5 * * * * /path/to/script.sh >> /tmp/cron-debug.log 2>&1Check /tmp/cron-debug.log after the next scheduled run.
5. Verify the Crontab Syntax
crontab -l # review what is actually installedA common mistake is editing the crontab file with nano /var/spool/cron/crontabs/user directly, which can corrupt permissions and cause cron to silently ignore the file.
Cron Alternatives
Cron is not always the right tool:
| Alternative | When to Use It |
|---|---|
| systemd timers | Modern Linux systems — better logging, transient units, dependency management |
| Airflow / Prefect | Complex data pipelines with dependencies, retries, and observability |
| Celery Beat | Django/Python apps that already use Celery |
| node-cron / node-schedule | Node.js apps that need in-process scheduling |
| APScheduler (Python) | Python apps needing in-process scheduling |
| Cloud schedulers | Serverless functions, managed infrastructure without persistent servers |
| Kubernetes CronJob | Containerized workloads in a K8s cluster |
Systemd timers deserve a special mention. On any system running systemd, timers are a more robust alternative to cron for system-level jobs. They log to the journal, support OnCalendar expressions (similar to cron but with readable syntax like daily or Mon *-*-* 09:00:00), and integrate with service dependencies.
Quick Reference Card
# Cron expression format:
# MIN HOUR DOM MON DOW COMMAND
# Special characters:
# * every valid value
# , list: 1,3,5
# - range: 1-5
# / step: */15 (every 15)
# Examples:
* * * * * every minute
*/5 * * * * every 5 minutes
0 * * * * top of every hour
0 6 * * * 6 AM daily
30 9 * * 1-5 9:30 AM weekdays
0 0 1 * * midnight on 1st of month
0 0 1 1 * midnight on Jan 1 (yearly)
0 6,18 * * * 6 AM and 6 PM daily
0 9 * * 1 9 AM every Monday
*/15 9-17 * * 1-5 every 15 min, 9-5, weekdaysConclusion
Cron is deceptively simple on the surface — five fields — but full of subtleties that have tripped up every developer who works with it seriously. The OR behavior of day-of-month and day-of-week, the minimal environment, timezone handling, and overlapping runs are the four areas that cause most production issues.
The good news: once you internalize those rules and adopt good habits (full paths, explicit output redirection, a lock file for long-running jobs, monitoring), cron is a remarkably reliable workhorse. It has been running without drama on Unix systems for five decades and will continue to do so.
For a visual way to build and validate cron expressions without memorizing the syntax, try the Cron Expression Builder. Paste any expression and it shows the next 10 scheduled run times, making it easy to verify your schedule before deploying it.
You might also like
What Is JSON? Complete Guide to JSON Formatting
What Is JSON? Complete Guide to JSON Formatting JSON — JavaScript Object Notation — is the lingua fr…
Read moreHow to View CSV & Excel Files Online for Free
How to View CSV & Excel Files Online for Free Spreadsheet files are everywhere. Data exports from da…
Read moreHow to Analyze Any File Online: Format & Metadata Guide
How to Analyze Any File Online: Format & Metadata Guide Every file on your computer carries more inf…
Read more