crontab.guru is one of the best small dev tools on the internet. It explains a cron expression in plain English instantly. I've used it for ~8 years.
But every time I came back, I wanted three things it doesn't do.
So I built them. Live at cron.protodex.io — same dark-mode style, single page, no signup, runs offline. Here's what's different.
1. Plain English → cron (the reverse direction)
crontab.guru is cron → English. Once you've written cron three times, you don't need the explanation. You need help going the other way: "I want this to run every weekday morning at 9 — what's the cron?"
I added a generator. Type "every 15 minutes during business hours" → get back */15 9-17 * * 1-5. It's not full natural language (I haven't gone to NLP), but the common patterns work: "every X minutes", "every X hours", "daily at HH:MM", "weekly on DAY at HH:MM", "monthly on day N".
2. Next 10 actual run times
When you're debugging "did my cron actually fire?" you want to see: "next run is in 47 minutes, then 4 hours from now, then..." Most cron tools show the expression but not the upcoming firings.
The naive approach — increment a Date by one minute, test each — works but dies on sparse schedules:
while (out.length < 10) {
if (matchesAllFields(d)) out.push(new Date(d));
d.setMinutes(d.getMinutes() + 1);
}
That works for */5 * * * * (every 5 min) but dies on @yearly — you'd walk 525,600 minutes (one year) just to find the second run. Slow on V8, times out in browser.
Smart-skip fixes it:
while (out.length < 10) {
if (!matchesField(c.month, d.getMonth()+1)) {
d.setMonth(d.getMonth() + 1, 1); // jump to next month
d.setHours(0, 0, 0, 0);
continue;
}
if (!matchesField(c.dom, d.getDate())) {
d.setDate(d.getDate() + 1); // jump to next day
d.setHours(0, 0, 0, 0);
continue;
}
// ... same for hour, minute
out.push(new Date(d));
d.setMinutes(d.getMinutes() + 1);
}
@yearly now resolves in 3ms instead of timing out. Also correctly handles leap-year crons like 0 0 29 2 * — returns Feb 29 of 2028, 2032, 2036, 2040, 2044.
3. Systemd timer equivalent
Most modern Linux is systemd-first. Whenever I converted a cron job into a managed service, I had to mentally translate 0 9 * * 1-5 into:
[Timer]
OnCalendar=Mon..Fri *-*-* 09:00:00
Persistent=true
RandomizedDelaySec=30
[Install]
WantedBy=timers.target
The tool generates the full [Timer] block side-by-side with the cron explanation. With the sensible defaults baked in: Persistent=true (catch up on missed runs after reboot), RandomizedDelaySec=30 (avoid thundering herds on tight-fleet deploys).
What this is built on
Pure vanilla JS. No framework. No bundler. ~6KB minified. Source structure is two files: index.html (which has all the JS inline) and the shared protodex stylesheet.
Hosted on Cloudflare Pages free tier. Works offline once the page loads — there's no API call at runtime, the entire parser + describer + next-run calculator + systemd generator runs in your browser.
Edge cases I haven't handled
- 6-field Quartz format (with leading seconds) — only standard 5-field cron
- Year field — some forks (e.g. Synology) accept a 6th year field. Not supported.
-
Named days with mixed numeric —
MON-FRI,0,6works in some implementations. Not here.
Patches welcome if anyone hits these.
Try it: cron.protodex.io
This is part of protodex.io — a small set of free tools focused on dev utilities and Indian compliance.
Top comments (0)