{"id":51008429,"url":"https://github.com/voidd0/cronwtf","last_synced_at":"2026-06-20T23:31:06.101Z","repository":{"id":353200379,"uuid":"1218377961","full_name":"voidd0/cronwtf","owner":"voidd0","description":"decode any cron expression in plain english. ~3 KB, zero deps.","archived":false,"fork":false,"pushed_at":"2026-04-29T06:13:57.000Z","size":19,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-15T20:46:11.075Z","etag":null,"topics":["cli","cron","cron-expression","crontab","devtools","expression-parser","javascript","nodejs","npm-package","scheduling"],"latest_commit_sha":null,"homepage":"https://tools.voiddo.com/cronwtf/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/voidd0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-22T20:18:17.000Z","updated_at":"2026-04-29T06:14:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/voidd0/cronwtf","commit_stats":null,"previous_names":["voidd0/cronwtf"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/voidd0/cronwtf","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fcronwtf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fcronwtf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fcronwtf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fcronwtf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/voidd0","download_url":"https://codeload.github.com/voidd0/cronwtf/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/voidd0%2Fcronwtf/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34589204,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cron","cron-expression","crontab","devtools","expression-parser","javascript","nodejs","npm-package","scheduling"],"created_at":"2026-06-20T23:31:03.747Z","updated_at":"2026-06-20T23:31:06.092Z","avatar_url":"https://github.com/voidd0.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cronwtf\n\n[![npm version](https://img.shields.io/npm/v/@v0idd0/cronwtf.svg?color=A0573A)](https://www.npmjs.com/package/@v0idd0/cronwtf)\n[![npm downloads](https://img.shields.io/npm/dw/@v0idd0/cronwtf.svg?color=1F1A14)](https://www.npmjs.com/package/@v0idd0/cronwtf)\n[![License: MIT](https://img.shields.io/badge/license-MIT-A0573A.svg)](LICENSE)\n[![Node ≥14](https://img.shields.io/badge/node-%E2%89%A514-1F1A14)](package.json)\n\n**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`).\n\nFree forever gift from [vøiddo](https://voiddo.com).\n\n```\n$ cronwtf \"0 9 * * 1-5\"\n\n  0 9 * * 1-5\n\n  → At 9:00 AM, on weekdays\n\n  Next 5 runs:\n    2026-04-23 09:00:00  in 10h\n    2026-04-24 09:00:00  in 1d\n    2026-04-27 09:00:00  in 4d\n    2026-04-28 09:00:00  in 5d\n    2026-04-29 09:00:00  in 6d\n```\n\n## Why cronwtf\n\nNobody 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.)\n\n`cronwtf` is the quick sanity check you run before pasting into your crontab:\n- **explains** the expression in one readable sentence,\n- **previews** the next N runs in your local timezone,\n- **warns** about the 4 most common foot-guns: impossible dates, DOM+DOW overlap, every-minute runs, leap-year-only rules,\n- **diffs** two expressions field-by-field so you can see what changed in a PR,\n- **lists** 15 common patterns if you just want the recipe,\n- **estimates frequency** over 30 days (runs/day, runs/week, runs/month).\n\n## Install\n\n```bash\nnpm install -g @v0idd0/cronwtf\n```\n\nOr one-shot with `npx`:\n\n```bash\nnpx -y @v0idd0/cronwtf \"@hourly\"\n```\n\n## Quickstart\n\n```bash\n# Plain explain + next 5 runs\ncronwtf \"0 9 * * 1-5\"\n\n# Aliases work\ncronwtf @daily\ncronwtf @hourly -n 3\n\n# Named months/weekdays\ncronwtf \"0 9 * * MON-FRI\"\ncronwtf \"0 0 1 JAN,JUL *\"\n\n# Catch gotchas (exit code 2 on impossible dates)\ncronwtf \"0 0 31 2 *\"\n\n# Machine-readable output\ncronwtf \"*/15 * * * *\" --json\n\n# Frequency estimate\ncronwtf \"0 9 * * 1-5\" --freq\n\n# Field-level diff between two expressions\ncronwtf diff \"0 9 * * *\" \"0 10 * * 1-5\"\n\n# 15 common patterns with their English meanings\ncronwtf patterns\n\n# CI validator: exit 0 (valid) / 1 (invalid) / 2 (valid but will-never-fire)\ncronwtf \"$CRON_EXPR\" --validate \u0026\u0026 echo OK\n\n# Times in UTC instead of local\ncronwtf @daily --utc\n```\n\n## Gotchas cronwtf catches\n\n| Pattern | Warning |\n|---------|---------|\n| `0 0 31 2 *` | `ERROR` — Day 31 does not exist in February. Never fires. |\n| `0 0 15 * 1` | `WARN` — DOM **and** DOW set. Cron runs when **either** matches (OR, not AND). |\n| `* * * * *` | `INFO` — Fires every minute. Usually you want `*/5` or `0 * * * *`. |\n| `0 0 29 2 *` | `INFO` — Feb 29 only exists in leap years. ~4-year gaps. |\n\nThese are the top crash causes in real cron outages. Catching them at paste-time is cheaper than at 3 AM.\n\n## Options\n\n### Core\n| Flag | Description |\n|------|-------------|\n| `-n, --next \u003cN\u003e` | Next N run times (default 5) |\n| `-j, --json` | Machine-readable output |\n| `-v, --validate` | Exit only; code 0=valid, 1=invalid, 2=never-fires |\n| `--freq` | Runs/day, /week, /month over next 30 days |\n| `--no-warnings` | Skip gotcha detection |\n| `--utc` | Print times in UTC instead of local |\n| `-h, --help` | Show help |\n| `--version` | Print version |\n\n### Subcommands\n| Command | Description |\n|---------|-------------|\n| `cronwtf diff \u003ca\u003e \u003cb\u003e` | Show field-level differences between two expressions |\n| `cronwtf patterns` | List 15 common cron recipes with English meanings |\n\n## Supported syntax\n\n| Syntax | Example | Meaning |\n|--------|---------|---------|\n| `*` | `* * * * *` | Any value |\n| `*/N` | `*/15 * * * *` | Every N units |\n| `A-B` | `0 9 * * 1-5` | Range |\n| `A,B,C` | `0 12 * * 1,3,5` | List |\n| `A-B/N` | `0 9-17/2 * * 1-5` | Range with step |\n| `@yearly` | — | `0 0 1 1 *` |\n| `@annually` | — | `0 0 1 1 *` |\n| `@monthly` | — | `0 0 1 * *` |\n| `@weekly` | — | `0 0 * * 0` |\n| `@daily` / `@midnight` | — | `0 0 * * *` |\n| `@hourly` | — | `0 * * * *` |\n| Named months | `JAN`, `FEB`, ..., `DEC` | 1–12 |\n| Named weekdays | `SUN`, `MON`, ..., `SAT` | 0–6 |\n\n## Programmatic use\n\n```js\nconst {\n  parseCron,        // \"0 9 * * 1-5\" → \"At 9:00 AM, on weekdays\"\n  getNextRuns,      // (expr, count) → Date[]\n  isValidCron,      // (expr) → boolean\n  analyzeWarnings,  // (expr) → Warning[]  (DOM_AND_DOW, IMPOSSIBLE_DATE, etc.)\n  diffExpressions,  // (a, b) → [{field, a, b}, ...]\n  describeFrequency,// (expr, windowDays) → {runsInWindow, runsPerDay, ...}\n  normalizeAliases, // \"@daily\" → \"0 0 * * *\"\n  COMMON_PATTERNS,  // Array of {expr, meaning}\n} = require('@v0idd0/cronwtf/src/parser');\n\n// In a PR-bot:\nfor (const expr of pullRequest.changedCronExpressions) {\n  const warnings = analyzeWarnings(expr);\n  if (warnings.some(w =\u003e w.level === 'error')) {\n    github.comment(`⚠ ${expr} — ${warnings[0].message}`);\n  }\n}\n```\n\n## Exit codes\n\n| Code | Meaning |\n|------|---------|\n| `0`  | Valid, no errors |\n| `1`  | Invalid syntax |\n| `2`  | Syntactically valid but will never fire (impossible-date warning) |\n\nUseful in CI:\n\n```yaml\n- run: cronwtf \"$CRON_EXPR\" --validate\n```\n\n## From the same studio\n\nvøiddo builds sharp, free-forever CLIs for devs who are tired of paywalls:\n\n- [`@v0idd0/jsonyo`](https://voiddo.com/tools/jsonyo/) — JSON that yells at you\n- [`@v0idd0/tokcount`](https://voiddo.com/tools/tokcount/) — token counter for 60+ LLMs\n- [`@v0idd0/ctxstuff`](https://voiddo.com/tools/ctxstuff/) — stuff a repo into an LLM context\n- [`@v0idd0/promptdiff`](https://voiddo.com/tools/promptdiff/) — diff two prompts\n- [`@v0idd0/httpwut`](https://voiddo.com/tools/httpwut/) — HTTP debugger\n- [`@v0idd0/gitstats`](https://voiddo.com/tools/gitstats/) — local git analytics\n- [`@v0idd0/licenseme`](https://voiddo.com/tools/licenseme/) — LICENSE generator + detector\n- [`@v0idd0/envguard`](https://voiddo.com/tools/envguard/) — .env validator + secret scanner\n- [`@v0idd0/depcheck`](https://voiddo.com/tools/depcheck/) — offline CVE scanner + unused-deps\n- [`@v0idd0/logparse`](https://voiddo.com/tools/logparse/) — structured log parser + aggregator\n\nFull catalog: [voiddo.com/tools](https://voiddo.com/tools/).\n\n## License\n\nMIT © [vøiddo](https://voiddo.com) — free forever, no asterisks.\n\n## Links\n\n- Docs: https://voiddo.com/tools/cronwtf/\n- Source: https://github.com/voidd0/cronwtf\n- npm: https://npmjs.com/package/@v0idd0/cronwtf\n- Studio: https://voiddo.com\n- Issues: https://github.com/voidd0/cronwtf/issues\n- Support: support@voiddo.com\n\n---\n\nBuilt by [vøiddo](https://voiddo.com/) — a small studio shipping AI-flavoured products, free dev tools, Chrome extensions and weird browser games.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoidd0%2Fcronwtf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvoidd0%2Fcronwtf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvoidd0%2Fcronwtf/lists"}