Skip to content

voidd0/cronwtf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cronwtf

Explain cron expressions in plain English. Preview next run times. Catch common gotchas (Feb 31, DOM+DOW overlap, accidental every-minute runs) before they fire. Handles @daily/@hourly/@yearly aliases and named weekdays/months (MON-FRI, JAN,JUL).

Free forever gift from vøiddo.

$ cronwtf "0 9 * * 1-5"

  0 9 * * 1-5

  → At 9:00 AM, on weekdays

  Next 5 runs:
    2026-04-23 09:00:00  in 10h
    2026-04-24 09:00:00  in 1d
    2026-04-27 09:00:00  in 4d
    2026-04-28 09:00:00  in 5d
    2026-04-29 09:00:00  in 6d

Why cronwtf

Nobody remembers cron syntax. 0 */2 * * * — is that every 2 hours or every 2 minutes? Does 0 0 15 * 1 run on the 15th OR on Mondays? (Answer: both — cron uses OR for DOM+DOW, and that's caused outages.) Does 0 0 31 2 * ever run? (Answer: never — Feb doesn't have a 31st.)

cronwtf is the quick sanity check you run before pasting into your crontab:

  • explains the expression in one readable sentence,
  • previews the next N runs in your local timezone,
  • warns about the 4 most common foot-guns: impossible dates, DOM+DOW overlap, every-minute runs, leap-year-only rules,
  • diffs two expressions field-by-field so you can see what changed in a PR,
  • lists 15 common patterns if you just want the recipe,
  • estimates frequency over 30 days (runs/day, runs/week, runs/month).

Install

npm install -g @v0idd0/cronwtf

Or one-shot with npx:

npx -y @v0idd0/cronwtf "@hourly"

Quickstart

# Plain explain + next 5 runs
cronwtf "0 9 * * 1-5"

# Aliases work
cronwtf @daily
cronwtf @hourly -n 3

# Named months/weekdays
cronwtf "0 9 * * MON-FRI"
cronwtf "0 0 1 JAN,JUL *"

# Catch gotchas (exit code 2 on impossible dates)
cronwtf "0 0 31 2 *"

# Machine-readable output
cronwtf "*/15 * * * *" --json

# Frequency estimate
cronwtf "0 9 * * 1-5" --freq

# Field-level diff between two expressions
cronwtf diff "0 9 * * *" "0 10 * * 1-5"

# 15 common patterns with their English meanings
cronwtf patterns

# CI validator: exit 0 (valid) / 1 (invalid) / 2 (valid but will-never-fire)
cronwtf "$CRON_EXPR" --validate && echo OK

# Times in UTC instead of local
cronwtf @daily --utc

Gotchas cronwtf catches

Pattern Warning
0 0 31 2 * ERROR — Day 31 does not exist in February. Never fires.
0 0 15 * 1 WARN — DOM and DOW set. Cron runs when either matches (OR, not AND).
* * * * * INFO — Fires every minute. Usually you want */5 or 0 * * * *.
0 0 29 2 * INFO — Feb 29 only exists in leap years. ~4-year gaps.

These are the top crash causes in real cron outages. Catching them at paste-time is cheaper than at 3 AM.

Options

Core

Flag Description
-n, --next <N> Next N run times (default 5)
-j, --json Machine-readable output
-v, --validate Exit only; code 0=valid, 1=invalid, 2=never-fires
--freq Runs/day, /week, /month over next 30 days
--no-warnings Skip gotcha detection
--utc Print times in UTC instead of local
-h, --help Show help
--version Print version

Subcommands

Command Description
cronwtf diff <a> <b> Show field-level differences between two expressions
cronwtf patterns List 15 common cron recipes with English meanings

Supported syntax

Syntax Example Meaning
* * * * * * Any value
*/N */15 * * * * Every N units
A-B 0 9 * * 1-5 Range
A,B,C 0 12 * * 1,3,5 List
A-B/N 0 9-17/2 * * 1-5 Range with step
@yearly 0 0 1 1 *
@annually 0 0 1 1 *
@monthly 0 0 1 * *
@weekly 0 0 * * 0
@daily / @midnight 0 0 * * *
@hourly 0 * * * *
Named months JAN, FEB, ..., DEC 1–12
Named weekdays SUN, MON, ..., SAT 0–6

Programmatic use

const {
  parseCron,        // "0 9 * * 1-5" → "At 9:00 AM, on weekdays"
  getNextRuns,      // (expr, count) → Date[]
  isValidCron,      // (expr) → boolean
  analyzeWarnings,  // (expr) → Warning[]  (DOM_AND_DOW, IMPOSSIBLE_DATE, etc.)
  diffExpressions,  // (a, b) → [{field, a, b}, ...]
  describeFrequency,// (expr, windowDays) → {runsInWindow, runsPerDay, ...}
  normalizeAliases, // "@daily" → "0 0 * * *"
  COMMON_PATTERNS,  // Array of {expr, meaning}
} = require('@v0idd0/cronwtf/src/parser');

// In a PR-bot:
for (const expr of pullRequest.changedCronExpressions) {
  const warnings = analyzeWarnings(expr);
  if (warnings.some(w => w.level === 'error')) {
    github.comment(`⚠ ${expr}${warnings[0].message}`);
  }
}

Exit codes

Code Meaning
0 Valid, no errors
1 Invalid syntax
2 Syntactically valid but will never fire (impossible-date warning)

Useful in CI:

- run: cronwtf "$CRON_EXPR" --validate

From the same studio

vøiddo builds sharp, free-forever CLIs for devs who are tired of paywalls:

Full catalog: voiddo.com/tools.

License

MIT © vøiddo — free forever, no asterisks.

Links

About

Explain cron expressions in plain English. Preview next runs. Catch gotchas (Feb 31, DOM+DOW overlap). Free forever from vøiddo.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors