Cron Expression Explainer

Cron expressions are the backbone of automated computing, yet deciphering shorthand like */15 9-17 * * 1-5 or special tokens like L and # is notoriously error-prone. This free explainer converts standard 5-field and 6-field cron expressions into clear, human-readable English, audits field constraints, calculates estimated annual runs, and calculates your exact next 5 execution timestamps in either your local browser timezone or UTC. Everything evaluates 100% client-side with zero data leaving your browser.

Free DevOps & Engineering Tool · 100% In-Browser

Translate & inspect any cron expression

Converts crontab schedules into plain English, audits field boundaries, and calculates upcoming run timestamps instantly.

  • Plain-English translation
  • Next 5 run times
  • Local & UTC zones
  • 5-field & 6-field

Expression & configuration

Supports standard POSIX crontab (5 fields), 6-field with seconds, and nicknames like @daily, @weekly, @hourly.

Field-by-field breakdown

Schedule analysis & next runs

100%
VALID SCHEDULE

All fields parse cleanly within valid standard boundaries.

HUMAN-READABLE SCHEDULE */15 9-17 * * 1-5

Every 15 minutes, between 09:00 AM and 05:00 PM, Monday through Friday

  • Annual runs 9,396 / yr
  • Interval 15 min
  • Frequency tier Business Hours
  • Active fields 5 / 5 Matched

Next 5 projected executions

Timezone: Local
Cron expression parsed. Valid schedule.

How Cron Expressions Work: The 5-Field Standard vs 6-Field Extensions

Originally introduced in Version 7 Unix in 1979, the cron daemon (crond) allows system administrators and software developers to execute automated commands or scripts at recurring calendar intervals. While modern DevOps teams deploy jobs via Kubernetes CronJobs, AWS EventBridge, Google Cloud Scheduler, or GitHub Actions, standard Unix crontab notation remains the universal standard for describing scheduled execution times.

A standard POSIX crontab expression consists of five whitespace-delimited fields that specify the exact minute, hour, day of the month, month, and day of the week when a command should trigger. Advanced enterprise job schedulers—such as Quartz in Java, Spring Framework, and Quartz-based enterprise workflow engines—frequently extend this syntax to six fields by prefixing a dedicated Seconds field, allowing sub-minute execution precision.

Field Position Field Name Allowed Values Special Characters Field Purpose & Operational Meaning
Field 1 (Optional) Seconds 0–59 * , - / Second of the minute (6-field schedulers only; Quartz, Spring, AWS EventBridge).
Field 1 / 2 Minute 0–59 * , - / Minute past the hour when the job is triggered.
Field 2 / 3 Hour 0–23 * , - / Hour of the day in 24-hour military notation (0 = midnight, 12 = noon, 23 = 11:00 PM).
Field 3 / 4 Day of Month 1–31 * , - / ? L W Calendar day of the month (1 to 31, depending on the active calendar month).
Field 4 / 5 Month 1–12 or JAN–DEC * , - / Calendar month of the year (1 = January, 12 = December; case-insensitive 3-letter codes).
Field 5 / 6 Day of Week 0–7 or SUN–SAT * , - / ? L # Weekday of execution. Note: In POSIX crontab, both 0 and 7 represent Sunday.

Special Characters and Pattern Modifiers Explained

The expressive power of crontab lies in its eight core modifier characters. Understanding their exact syntactic semantics is critical to avoiding unintended continuous execution loops or skipped execution windows:

  • Asterisk (*): Wildcard representing every possible value in that field. In the minute field, * triggers every single minute. In the month field, * triggers during all 12 calendar months.
  • Comma (,): Value list separator. Specifies a discrete, discontinuous set of values. For example, 15,45 in the minute field runs at minute 15 and minute 45 of matching hours.
  • Hyphen (-): Inclusive range operator. Specifies a continuous boundary from start to end. For example, 9-17 in the hour field triggers every hour from 09:00 through 17:00 (5:00 PM) inclusive.
  • Forward Slash (/): Step interval modifier. Specifies increments across a range or wildcard. For example, */15 in the minute field evaluates to 0, 15, 30, 45. Similarly, 10-50/20 evaluates to minutes 10, 30, and 50.
  • Question Mark (?): Non-specific value placeholder. Used in modern cloud and Quartz schedulers where specifying both a Day-of-Month and a Day-of-Week would create syntactic ambiguity. In standard Unix crontab, * serves this purpose.
  • L Token (L): Shorthand for “Last”. In the day-of-month field, L automatically resolves to the final calendar day of that specific month (e.g. 28/29 for February, 30 for April, 31 for October). In the day-of-week field, 5L specifies the last Friday of the month.
  • W Token (W): Nearest weekday operator. In the day-of-month field, 15W evaluates to the closest working weekday (Monday through Friday) to the 15th calendar day. If the 15th falls on a Saturday, it triggers on Friday the 14th; if on a Sunday, it triggers on Monday the 16th.
  • Hash Symbol (#): N-th occurrence operator. In the day-of-week field, 2#3 instructs the daemon to trigger on the third Tuesday of the month (where 2 is Tuesday and 3 is the 3rd occurrence).

The Day-of-Month vs Day-of-Week Conflict: The POSIX Crontab OR Quirk

One of the most persistent traps in systems engineering is the interaction between Field 3 (Day of Month) and Field 5 (Day of Week). Most developers intuitively assume all cron fields evaluate using boolean AND logic. However, the official IEEE Std 1003.1 (POSIX) specification introduces a deliberate exception for the day fields:

“If both the day of the month and day of the week fields are restricted (that is, neither is an asterisk or question mark), the command will be run when either field matches the current date.”

Consider the expression 0 0 1,15 * 1. A developer might assume this schedules a job to run only when the 1st or 15th of the month happens to be a Monday. In standard Linux cron (such as Vixie Cron or Cronie), this actually triggers on the 1st of every month, on the 15th of every month, AND on every single Monday throughout the month. If strict boolean intersection is required in bash, engineers must check the date inside the executed command wrapper:

0 0 1,15 * * [ $(date +\%u) -eq 1 ] && /usr/local/bin/run-backup.sh

Scheduling Best Practices: Preventing the “Thundering Herd” Problem

In high-scale enterprise environments and marketing automation pipelines, naive cron scheduling frequently causes severe infrastructure outages. Review these operational guidelines before deploying production schedules:

  1. Stagger Top-of-Hour Jobs: Over 70% of developer-written cron jobs are configured to run at minute 0 (e.g. 0 * * * * or 0 0 * * *). When hundreds of microservices, database dumps, and analytics syncs trigger simultaneously at midnight, CPU utilization spikes, disk I/O saturates, and third-party API rate limits are instantly exhausted. Offset your schedule by an arbitrary minute offset (e.g. 17 2 * * * instead of 0 2 * * *).
  2. Match Server Timezones (UTC vs Local): Production servers, container clusters, and database nodes should universally operate in UTC (Coordinated Universal Time). Scheduling cron jobs in local daylight saving time (DST) zones causes jobs to execute twice when clocks fall back in autumn, and skip execution entirely when clocks spring forward in spring.
  3. Enforce Overlap Prevention with Flocks: Cron launches processes blind to whether previous instances have terminated. If a backup job configured with 0 * * * * takes 75 minutes due to heavy network latency, a second instance will spawn while the first is running, leading to database lock deadlocks. Use flock or run-one to prevent concurrent duplicate runs:
    0 * * * * /usr/bin/flock -n /var/lock/backup.lock /usr/local/bin/backup-script.sh
  4. Redirect Output Explicitly: By default, POSIX cron attempts to mail standard output and standard error to the local root user mailbox via sendmail. On servers lacking an active mail transfer agent (MTA), this generates discarded errors or inflates /var/mail/ disk space. Always route log output directly to syslog or a centralized log collector:
    0 4 * * * /usr/local/bin/nightly-audit.sh >> /var/log/audit.log 2>&1

Cron vs Systemd Timers vs Cloud Schedulers

While traditional crontab remains popular due to its brevity, modern production architectures frequently employ dedicated task engines. Compare the standard operational trade-offs across deployment targets:

Scheduling Architecture Configuration Format Sub-Minute Precision Failure Recovery & Catch-Up Primary Use Case
POSIX Linux Crontab 5-field text table (crontab -e) No (1 minute minimum) No (skipped runs are lost) Standard server administration, local developer utilities, simple batch scripts.
Systemd Timers .timer unit files (Calendar notation) Yes (microsecond resolution) Yes (Persistent=true catches up missed runs after downtime) Modern Linux service management, OS maintenance, resource-isolated cgroups.
Kubernetes CronJobs YAML Pod specifications (POSIX cron syntax) No (1 minute minimum) Yes (configurable startingDeadlineSeconds and concurrency policy) Containerized microservices, distributed cluster batch processing.
AWS EventBridge / CloudWatch 6-field cron or rate expressions No (1 minute minimum) Yes (managed dead-letter queues and automated retries) Serverless AWS Lambda triggers, cross-account cloud automation.

Common Production Cron Schedule Reference Table

Quickly look up verified crontab syntax strings for the most common engineering schedules:

Execution Objective Crontab Expression Normalized Human Cadence Estimated Annual Executions
Every 5 Minutes */5 * * * * Minutes 0, 5, 10, 15… 55 of every hour 105,120 runs / year
Every 15 Minutes (Business Hours) */15 9-17 * * 1-5 Every 15 mins between 09:00 and 17:00, Mon–Fri 9,396 runs / year
Hourly at Top of Hour 0 * * * * At minute 0 of every single hour 8,760 runs / year
Every Night at Midnight 0 0 * * * (or @daily) At 00:00 (12:00 AM) every day 365 runs / year
Weekdays at 08:30 AM 30 8 * * 1-5 At 08:30 AM, Monday through Friday 261 runs / year
Weekly on Sunday at 03:00 AM 0 3 * * 0 (or @weekly) At 03:00 AM every Sunday morning 52 runs / year
First Day of Every Month 0 0 1 * * (or @monthly) At 00:00 on the 1st of every month 12 runs / year
Last Day of Every Month 0 0 L * * At 00:00 on the final day of every month 12 runs / year
Quarterly Financial Report 0 0 1 1,4,7,10 * Midnight on Jan 1, Apr 1, Jul 1, and Oct 1 4 runs / year
Annual New Year Run 0 0 1 1 * (or @yearly) At 00:00 on January 1st 1 run / year

Frequently Asked Questions About Cron Expressions

What is the difference between * (asterisk) and ? (question mark) in cron?

In standard POSIX Linux crontab, the question mark (?) is not historically defined; standard cron uses * for all unconstrained fields. However, in enterprise schedulers like Quartz, Spring, and AWS EventBridge, ? is explicitly required in either the day-of-month or day-of-week field to indicate “no specific value.” In these systems, specifying an asterisk in both fields simultaneously triggers a syntax validation error because the scheduler refuses to evaluate two concurrent day constraints.

Why did my cron job run twice or skip during Daylight Saving Time?

If your operating system timezone is set to a regional zone like America/New_York or Europe/London, cron observes local wall-clock shifts. In the spring, when the clock jumps from 01:59 AM to 03:00 AM, jobs scheduled between 02:00 and 02:59 AM are skipped completely because those minutes never occurred. Conversely, in autumn when clocks fall back from 02:00 AM to 01:00 AM, that entire hour repeats, causing nightly batch jobs to execute twice. Prevent this by locking server hardware and daemon clocks to UTC.

Can cron run a script every 30 seconds?

Standard Unix crond has a fundamental resolution limit of one minute (60 seconds); the minute field cannot evaluate sub-minute increments. To run a script every 30 seconds on a legacy Linux system without third-party tools, engineers typically configure two parallel cron entries where the second command sleeps for 30 seconds:
* * * * * /usr/local/bin/sync-data.sh
* * * * * sleep 30; /usr/local/bin/sync-data.sh
Alternatively, migrate the job to a modern Systemd Timer with OnUnitActiveSec=30s or a 6-field scheduler supporting second-level resolution.

What environment variables does crontab load by default?

Cron executes commands in an extremely restricted, non-interactive shell environment. It does not source ~/.bashrc, ~/.bash_profile, or /etc/profile. As a result, the default $PATH is typically stripped down to /usr/bin:/bin, meaning custom binary paths like /usr/local/bin, node, python3, or nvm will trigger “command not found” errors. Always define explicit absolute binary paths in your crontab or declare PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin at the top of your crontab file.

How does the step syntax */10 differ from 10/10?

The syntax */10 in the minute field instructs cron to evaluate every 10th minute across the entire range (0–59), triggering at minutes 0, 10, 20, 30, 40, 50. In contrast, 10/10 specifies starting at minute 10 and advancing by 10 through the remainder of the hour, triggering at minutes 10, 20, 30, 40, 50 (omitting minute 0). For wildcards, */N is shorthand for 0-59/N in the minute field or 0-23/N in the hour field.