Cron and Daylight Saving Time: When a Nightly Job Runs Twice, or Not at All
Your cron job ran an hour early. Then it didn't run. Daylight saving breaks naive cron expressions — and there's a second trap hiding in day-of-month vs day-of-week nobody expects.
You scheduled a database backup for 2:00 a.m. every night. After the time change, it runs at 1:00 a.m. Then your site is down because a report ran twice. The crontab looks perfect. The problem isn't your expression — it's that cron doesn't know what time is.
Cron Is a Dumb Clock
A cron expression just says "run when the wall clock matches." It has no concept of daylight saving time. When clocks spring forward, the hour from 2:00 to 3:00 doesn't exist — a job at 0 2 * * * simply doesn't fire. When clocks fall back, 1:30 a.m. happens twice — a job at 30 1 * * * runs twice. Most operators hit this exactly once and then swear forever at the scheduler.
The Fix Is Boring and Reliable: UTC
Counter-intuitive but true: the way to make cron immune to DST is to not use your local timezone at all. Run jobs in UTC (TZ=UTC in the crontab, or the platform default on managed schedulers) and the clock never jumps. If a job genuinely needs to run at a local time — "9 a.m. for the East Coast" — that's a business-time problem, and the schedule changes at DST boundaries by design. Decide up front which hours are "server time" and which are "human time," and never mix them in one crontab.
The Second Trap: Day-of-Month AND Day-of-Week
The less famous gotcha lives in fields 3 and 5. In standard cron, if you restrict BOTH the day-of-month and the day-of-week, the job runs when EITHER matches — they're OR'd, not AND'd. So 0 2 1 * 1 does not mean "the first of the month when it's a Monday." It means "every first of the month AND every Monday." A real "first Monday of the month" needs extra logic. Before you deploy, run the expression through a cron parser and read the exact matches it reports — and when you're thinking in epoch seconds, the unix timestamp tool keeps the numbers straight.
Timezone mistakes are the classic source of "why did my job run at 3 a.m." — we covered them in our guide to cron timezone traps. Schedule in UTC, watch the OR logic, and verify every expression before it fires.
Tools mentioned in this article
Cron Expression Parser
Parse cron expressions and see when your scheduled jobs will run. Get human-readable descriptions and the next 10 execution times. Supports all 5-field standard cron syntax — no server needed.
Unix Timestamp Converter
Convert Unix timestamps to human-readable dates and vice versa. Supports seconds and milliseconds. Shows UTC and local time side by side. Pick a date to get its timestamp.
Hash Generator
Generate SHA-1, SHA-256, SHA-384, and SHA-512 hashes from any text. Also supports MD5 for legacy checks. Compare two hashes side by side to verify file integrity.
