Building the cron builder for Quietbench, I started with an npm package for parsing and calculating next-run times. Get it working, move on. That lasted about a week.
The problem: the library handled standard cron fine, but broke on real edge cases — conditional OR/AND behavior when day-of-week and day-of-month are combined, step values inside ranges (1-10/2), and off-by-one errors around DST transitions. When I checked its output against standard cron engines, the mismatches showed up fast.
Why not patch it: the parsing and "next run time" logic were tightly coupled internally. Fixing one edge case risked breaking another. Writing something scoped to exactly what I needed was less work than fighting someone else's abstraction.
The rewrite keeps three things cleanly separate: tokenize/validate each field, normalize day-of-week/day-of-month interaction explicitly, and compute next executions by walking forward in time rather than solving algebraically. Slower in theory, irrelevant in practice — nobody notices a few milliseconds when they're reading 5 output times.
Building the cron builder for Quietbench, I started with an npm package for parsing and calculating next-run times. Get it working, move on. That lasted about a week.
The problem: the library handled standard cron fine, but broke on real edge cases — conditional OR/AND behavior when day-of-week and day-of-month are combined, step values inside ranges (1-10/2), and off-by-one errors around DST transitions. When I checked its output against standard cron engines, the mismatches showed up fast.
Why not patch it: the parsing and "next run time" logic were tightly coupled internally. Fixing one edge case risked breaking another. Writing something scoped to exactly what I needed was less work than fighting someone else's abstraction.
The rewrite keeps three things cleanly separate: tokenize/validate each field, normalize day-of-week/day-of-month interaction explicitly, and compute next executions by walking forward in time rather than solving algebraically. Slower in theory, irrelevant in practice — nobody notices a few milliseconds when they're reading 5 output times.
**The actual lesson: **reaching for a library first isn't wrong. But once I was spending more time reverse-engineering why the library disagreed with standard cron behavior than I would've spent writing the logic myself, that was the signal to just own it.
Live at quietbench.dev/cron-builder — curious if anyone finds an edge case it still gets wrong. reaching for a library first isn't wrong. But once I was spending more time reverse-engineering why the library disagreed with standard cron behavior than I would've spent writing the logic myself, that was the signal to just own it.
Live at quietbench.dev/cron-builder — curious if anyone finds an edge case it still gets wrong.
Top comments (0)