Cron Expression Explainer & Visualizer
Paste any cron expression to get a plain-English explanation and the next 10 scheduled run times. Supports 5-field standard cron, 6-field (with seconds), and shorthand like @daily, @weekly, @monthly.
Reading a Schedule Written in Five Fields
A cron expression is a compact string of five whitespace-separated fields β minute, hour, day-of-month, month, and day-of-week β that defines a recurring schedule, first introduced in Unix Version 7 and still the default scheduling primitive across Linux systems, container orchestrators, and CI/CD platforms today. Each field accepts a wildcard (*, meaning "every value"), a specific number, a range (1-5), a step (*/15), or a comma-separated list (0,15,30,45), and all five can be combined in the same expression β which is exactly what makes cron both compact and easy to misread.
For a DevOps or SRE engineer, a misread cron expression is not a cosmetic bug: it directly determines when a backup runs, when a certificate renewal job fires, or when a database maintenance window begins. This explainer exists because translating 0 2 * * 1 into "runs at 2:00 AM every Monday" reliably, in your head, under time pressure, during a code review, is harder than it looks.
Cron vs Newer Scheduling Options
Cron's five-field format has near-universal support but two structural limits worth knowing: it has no concept of timezone β a plain crontab runs in the server's local time, while Kubernetes CronJobs default to UTC β and it has no built-in retry, alerting, or overlap protection, so a job that crashes silently simply doesn't run again until its next scheduled tick. Newer schedulers layer solutions on top of the same five-field syntax rather than replacing it: AWS EventBridge Scheduler and Quartz both add an optional sixth seconds field and support per-rule timezones, while workflow orchestrators like Airflow or Temporal add retries, dependency graphs, and alerting around a cron-like trigger rather than reinventing the schedule syntax itself.
The practical trade-off: plain cron remains the right choice for a single, independent, idempotent task, such as log rotation or a nightly cleanup script, while anything needing retries, dependency ordering, or cross-timezone correctness benefits from a scheduler built on top of cron syntax rather than raw crontab entries scattered across servers.
Field-Order and Logic Traps in Cron Syntax
- Assuming day-of-month and day-of-week combine with AND logic: when both fields are restricted, most cron implementations OR them together β
0 0 15 * 1runs on the 15th of every month and every Monday, not only on Mondays that happen to fall on the 15th. - Forgetting which timezone the scheduler actually uses: a plain crontab runs in local server time, but Kubernetes CronJobs default to UTC β an unstated assumption here has caused more than one job to fire at an unexpected hour.
- Stacking every nightly job at exactly midnight: scheduling several unrelated batch jobs all at
0 0 * * *creates a resource contention spike the moment they all hit the same database or API simultaneously. - Treating cron as a retry mechanism: cron has no concept of failure β a job that errors out just sits silently until its next tick, so relying on "it'll just run again later" as a safety net instead of adding real alerting is a common and avoidable gap.
How a Swapped Field Turns Once-a-Day Into Sixty Times an Hour
One of the most common cron mistakes is a simple field-order swap: typing * 0 * * * when the intent was 0 0 * * *. Both look superficially similar and both mention "0" and midnight, but the asterisk sitting in the minute field means "every minute" β so instead of firing once at midnight, the job runs 60 times between 00:00 and 00:59 every single night. A lightweight health check might absorb this unnoticed for weeks; a database backup or report-generation job turns it into 60x the expected load, duplicate output files, or a downstream system hit with near-simultaneous triggers it wasn't built to handle.
This class of mistake is specifically a field-order error, not a logic error, which is exactly why it survives casual review β the expression looks plausible at a glance and only a field-by-field read catches it. The mitigation that actually prevents it is mechanical rather than "read more carefully": render every new cron expression into plain English before it merges, exactly what this tool does, so a minute/hour swap is caught the moment it's written instead of after it's been running in production at 60x the intended frequency.
Checking Your Work at the Command Line
Every field this tool parses maps directly onto the crontab format read by crontab -e, and most Linux distributions ship a way to inspect an expression without waiting for it to fire: crontab -l lists installed jobs for review, and a quick man 5 crontab confirms field ranges when in doubt. For systemd-based systems, the equivalent construct is a timer unit's OnCalendar= directive, which uses a different but related calendar-event syntax β systemd-analyze calendar "Mon *-*-* 02:00:00" prints the next several trigger times directly from the command line, serving the same verification purpose as this page's next-run list but for systemd timers instead of crontab entries.
Frequently Asked Questions
What is a cron expression?
A cron expression is a string of five whitespace-separated fields that defines a recurring schedule: minute (0β59), hour (0β23), day-of-month (1β31), month (1β12), and day-of-week (0β7, where both 0 and 7 represent Sunday). For example, 0 9 * * 1-5 means "at 9:00 AM every weekday". Cron was originally introduced in Unix Version 7 and remains the standard scheduling primitive across Linux systems, container orchestrators, CI/CD platforms, and cloud-native schedulers alike.
What does the asterisk (*) mean in cron?
The asterisk means "every possible value" for that field. So * * * * * means every minute of every hour of every day. You can combine the asterisk with a step value: */5 in the minute field means "every 5 minutes", while */2 in the hour field means "every 2 hours". You can also use ranges like 1-5 to match a consecutive span, or comma-separated lists like 0,15,30,45 to match specific values β all of which can be mixed in a single expression.
How does cron syntax differ between Linux cron and Kubernetes CronJobs?
Standard Linux cron uses five fields (minute, hour, day-of-month, month, day-of-week) and runs in the local timezone of the server. Kubernetes CronJob spec uses the same five-field format but schedules are evaluated in UTC by default, and the job may start up to a minute late due to the controller's reconciliation interval β this is important to account for when scheduling time-sensitive operations. Some systems such as AWS EventBridge Scheduler, Spring @Scheduled, and Quartz add a sixth seconds field at the beginning of the expression, making those expressions incompatible with standard cron parsers and requiring careful documentation when sharing expressions across teams.