Parse cron expressions, compute the next/previous run times, and describe them in plain English — in ~2 KB, with zero dependencies.
"When does 0 9 * * 1-5 run next?" is a question you should never answer by
hand — and definitely shouldn't trust an LLM to guess. It's exact calendar
arithmetic (ranges, steps, month lengths, leap years, the day-of-month/day-of-week
union rule). croniq does it deterministically, and tells you in English.
import { parse } from "@didrod2539/croniq";
const cron = parse("0 9 * * 1-5"); // 09:00, weekdays
cron.next(); // → Date of the next weekday 09:00
cron.describe(); // "At 09:00, Monday through Friday"
cron.matches(new Date()); // is right now a run time?- 🎯 Correct, not approximate. Leap days, month lengths, and the Vixie-cron day-of-month OR day-of-week rule are all handled. Verified against known schedules in tests.
- ⚡ Fast. Field-jumping (not minute-by-minute scanning), so sparse schedules like
0 0 29 2 *resolve in microseconds. - 🗣️ Human-readable.
describe()turns an expression into a sentence — great for dashboards and confirmations. - 🧩 Full syntax. 5 fields or 6 (with seconds), ranges
1-5, lists1,3,5, steps*/15, namesJAN/MON,?, and macros@daily/@hourly/@weekly/… - 🕒 UTC or local. One flag.
- 🪶 ~2 KB gzipped, zero dependencies. Node 18+, Deno, Bun, Workers and the browser.
npm install @didrod2539/croniq
# or: pnpm add @didrod2539/croniq / yarn add @didrod2539/croniqPublished under the
@didrod2539npm scope (the unscoped namecroniqwas blocked by npm for being too close tocron). The import name matches the package name; everything else is identical.
Ships ESM and CommonJS:
import { parse, isValid } from "@didrod2539/croniq"; // ESM / TypeScript
const { parse, isValid } = require("@didrod2539/croniq"); // CommonJSnpx @didrod2539/croniq "0 9 * * 1" # describe + the next runs
npx @didrod2539/croniq describe "*/15 * * * *" # "Every 15 minutes"
npx @didrod2539/croniq next "0 0 1 * *" --iso -n 5
npx @didrod2539/croniq valid "61 * * * *" # exit 1 if invalidThe bundled command is croniq. Commands: describe, next, prev,
valid. Options: -n/--count, --utc, --iso. valid sets the exit code.
const cron = parse("*/15 * * * *"); // every 15 minutes
cron.next(); // next run after now
cron.next(new Date("2026-03-15T12:07Z")); // → 2026-03-15T12:15:00Z
cron.prev(); // previous run before now
cron.nextN(5); // next five runs (Date[])isValid("0 9 * * 1-5"); // true
isValid("99 * * * *"); // falseparse("0 9 * * 1-5").describe(); // "At 09:00, Monday through Friday"
parse("*/15 * * * *").describe(); // "Every 15 minutes"
parse("@hourly").describe(); // "At 0 minutes past every hour"
parse("0 0 1 1 *").describe(); // "At 00:00, on day-of-month 1, in January"parse("0 0 * * *", { utc: true }).next(); // midnights in UTC
parse("0 0 * * *").next(); // midnights in the host's local timeA 6-field expression adds a leading seconds column:
parse("*/30 * * * * *").next(); // every 30 seconds| Field | Values | Allowed |
|---|---|---|
| Second (opt.) | 0–59 | * , - / |
| Minute | 0–59 | * , - / |
| Hour | 0–23 | * , - / |
| Day of month | 1–31 | * , - / ? |
| Month | 1–12 or JAN–DEC |
* , - / |
| Day of week | 0–7 or SUN–SAT (0 & 7 = Sunday) |
* , - / ? |
Macros: @yearly / @annually, @monthly, @weekly, @daily / @midnight,
@hourly. When both day-of-month and day-of-week are restricted, a date matches
if either matches (standard cron behavior).
L,W, and#modifiers aren't supported yet — open an issue if you need them.
| Member | Description |
|---|---|
parse(expr, opts?) |
Parse into a Cron (throws on invalid input). |
isValid(expr, opts?) |
true/false without throwing. |
cron.next(from?) / cron.prev(from?) |
Next/previous run Date. |
cron.nextN(n, from?) / cron.prevN(n, from?) |
Arrays of run times. |
cron.matches(date?) |
Does the date satisfy the expression? |
cron.describe() |
Plain-English description. |
cron.minutes / .hours / .daysOfMonth / .months / .daysOfWeek / .seconds |
Parsed value arrays. |
croniq |
hand-rolled date math | heavier cron libs | |
|---|---|---|---|
| next / prev computation | ✅ | ✅ | |
| Plain-English describe | ✅ | ❌ | |
| Validation | ✅ | ❌ | ✅ |
| Zero dependencies | ✅ | ✅ | |
| ~2 KB gzipped | ✅ | — | ❌ |
Contributions are very welcome! Please read CONTRIBUTING.md and our Code of Conduct.
git clone https://github.com/didrod205/croniq.git
cd croniq
npm install
npm testcroniq is free and MIT-licensed, built and maintained in spare time. If it
saved you from debugging a misfiring schedule, please consider supporting it —
every bit helps keep the project healthy.
- ⭐ Star this repo — the simplest, free way to help others discover it.
- 🍋 Sponsor via Lemon Squeezy — one-time or recurring support.
Sponsoring? Open an issue and we'll add your name/logo here. Thank you! 🙏
MIT © croniq contributors