Cron expressions have caused me more 3 AM incidents than I care to admit. Here is my guide to validating them properly, plus every mistake I have made so you do not have to.
Why I built a cron validator
Here is a fun story: I once deployed a cron job meant to run weekly that actually ran every minute. For six hours. That database cleanup script deleted way more than intended. Since then, I always validate cron expressions before they hit production.
Cron syntax looks simple, but the edge cases are brutal. Wrong field order, timezone confusion, platform differences - I have been bitten by all of them at Šikulovi s.r.o..
The 5-field format I use daily
Standard cron is 5 fields, left to right: minute (0-59), hour (0-23), day of month (1-31), month (1-12), day of week (0-6, Sunday is 0). I remember it as "minutes matter most" since minute comes first.
- * * * * * runs every minute - use sparingly, this adds up fast
- 0 * * * * runs at the top of every hour - my go-to for hourly jobs
- 0 0 * * * runs at midnight daily - careful with timezones on this one
- 0 9 * * 1-5 runs at 9 AM weekdays - perfect for business-hours tasks
- */15 * * * * runs every 15 minutes - I use this for health checks
Mistakes I have made (so you do not have to)
I have made every single one of these errors. Some in production. Learn from my pain.
- Using 6 fields when the system expects 5 - some platforms add seconds, most do not
- Minute value of 60 - valid range is 0-59, I got burned by this once
- Hour value of 24 - valid range is 0-23, midnight is 0 not 24
- Day of week 7 - Sunday is 0, Saturday is 6, there is no 7
- Using */0 - step must be at least 1, */0 is not "never"
- Months 0-11 vs 1-12 - cron uses 1-12, unlike JavaScript Date
Special characters I use most
Beyond the basics, these special characters let me build complex schedules. I use */n constantly for intervals.
- * matches any value - the wildcard
- */n runs every n units - */5 for every 5 minutes, my most-used pattern
- n,m specifies multiple values - 1,15 for 1st and 15th of the month
- n-m defines a range - 1-5 means Monday through Friday
- L means last - great for month-end processing
- # specifies nth occurrence - 1#2 is the second Monday
Platform differences will trip you up
This caught me when I moved a cron from a Linux server to AWS EventBridge - completely different format. EventBridge uses 6 fields with year support. Quartz scheduler uses 6-7 fields with seconds. GitHub Actions is standard 5-field but always UTC.
I always check platform docs now before copy-pasting cron expressions. The syntax looks similar but the behavior differs.
The timezone trap
Cron runs in the server local timezone. This sounds fine until daylight saving time shifts your 2 AM backup job, or your container runs in UTC while you expected CET. I have learned to always document which timezone my crons expect.
For critical jobs, I use UTC exclusively now. It is one less variable that can break things at 3 AM.
My testing ritual before deployment
I never deploy a cron expression without validating it first. The tool shows me exactly when the next runs will happen. This catches off-by-one errors and timezone surprises before they become production incidents.
FAQ
Is my cron data secure when validating?
Yes - all validation runs in your browser. I built it this way because I would never paste production cron expressions into a tool that sends data to unknown servers.
What cron format does the validator support?
The standard 5-field format used by Linux crontab, Kubernetes CronJobs, and GitHub Actions. If you need AWS EventBridge or Quartz validation, those use different formats that I do not support yet.
Why does my cron expression show as invalid?
Usually it is wrong field count, out-of-range values, or invalid special characters. Double-check that you have exactly 5 fields and all numbers are within valid ranges. I have been bitten by all of these.
How do I schedule a job for the last day of the month?
Use L in the day-of-month field: "0 0 L * *" runs at midnight on the last day of every month. Fair warning - not all cron implementations support L.
Can I validate multiple cron expressions at once?
Yes - paste one expression per line and I will check each individually. I use this when auditing crontabs with dozens of entries.