GetCodingToolsGetCodingTools

Blog

Scheduled Jobs Need an Explicit Time-Zone Contract

2026-07-15

Back to Blog

A job described as “run every day at midnight” is incomplete. Midnight in which zone, and what should happen when daylight-saving time skips or repeats a local hour? Write the scheduling contract before debugging the cron expression: business zone, intended local time, late-run policy, duplicate-run policy, and the date key used for idempotency.

Store instants in UTC, but do not throw away the business zone. A subscription renewal for July 15 in Shanghai and a report for July 15 in Los Angeles refer to different UTC ranges. Calculate the start and end of the business day with a time-zone-aware library, then persist both the resulting instant and the zone used to derive it. A fixed offset such as UTC-8 is not a substitute for an IANA zone because offsets can change seasonally or historically.

Make the work idempotent around a business key such as daily-report:2026-07-15:Asia/Shanghai. If the scheduler retries after a network timeout or a deployment, the second run should detect completed work instead of sending the report twice. Record started, completed, and failed states separately so an interrupted run can resume safely rather than being mistaken for success.

Tests should cover more than an ordinary Tuesday. Include a daylight-saving transition in a zone that observes it, the end of a month, leap day, and a deployment that delays the job past its intended time. Decide whether a missed job runs immediately, waits for the next window, or enters a manual queue. Any of those can be valid, but an undocumented choice will eventually surprise someone.

When investigating production, log the scheduled local time, zone, resolved UTC instant, business date key, and attempt number. With those five values, an apparent “one-day offset” becomes a concrete conversion or retry problem rather than a debate about what the server clock displayed.