A scheduled job runs twice or not at all when clocks change
“The nightly job ran twice in November, or never ran one night in March, or now fires an hour early, and nobody touched the schedule.”
THE PRINCIPLE
The scheduler decides when to try; the job decides whether the work for that period is already done.
FIRST MOVES
- Find which zone the schedule is evaluated in: the host TZ for cron, kube-controller-manager's zone for a CronJob without .spec.timeZone, the configured zone for cloud schedulers.
- Prefer UTC for operational jobs; when the job must follow local business time, set an explicit IANA zone (America/New_York, not EST) and avoid 01:00-03:00.
- Key each run by the period it covers (for example the local business date) and claim it with a unique constraint, so a second trigger is a no-op.
- Compute periods from the scheduled time, not from now(), so a late or repeated trigger still processes the right day.
- Alert on missing runs as well as failed runs; a skipped job produces no error.
TOOLS: THEN → NOW
Crontab in the server's local time zoneUTC schedules, or Kubernetes CronJob .spec.timeZone (stable since v1.27) and cloud schedulers with an IANA zone
Assuming one trigger means one runPer-period run keys and Forbid concurrency, because schedulers may fire twice or not at all
PATTERN SNAPSHOT
// Claim the business day once; a repeated or late trigger becomes a no-op.
const day = new Intl.DateTimeFormat("en-CA", { timeZone: "America/New_York" })
.format(scheduledAt); // "2026-11-01", derived from the scheduled time, not now()
const claimed = await db.query(
`INSERT INTO job_runs (job, period) VALUES ('daily-report', $1)
ON CONFLICT (job, period) DO NOTHING RETURNING id`, [day]);
if (claimed.rowCount === 0) return; // done or running; expire stale claims to allow reruns
await buildDailyReport(day);
await db.query("UPDATE job_runs SET finished_at = now() WHERE job = 'daily-report' AND period = $1", [day]);CLOSE THE AI. EXPLAIN THIS.
A job is scheduled at 02:30 America/Los_Angeles. What happens on the spring-forward night under cronie, and under EventBridge Scheduler?RELATED SYMPTOMS
SOURCES
Guide reviewed