API timezone debugging checklist
Off-by-eight-hours bugs rarely come from “JavaScript Date is broken.” They come from mixed conventions: storing local time as if it were UTC, formatting UTC as local, or scheduling cron in a machine timezone nobody documented.
1. Write down the contract
- API request/response: ISO-8601 with offset? Always Z?
- Database column:
timestamptz, naive timestamp, or epoch integer? - Who converts: client, API, or database session timezone?
2. Capture one failing example end-to-end
Pick a single event. Record: user-visible local time, API payload, DB stored value, and log line. Convert each to epoch seconds with a known tool so you compare integers, not strings.
3. Check the usual suspects
- Server OS timezone vs container timezone vs orchestrator TZ env.
- ORM silently dropping offsets.
- Cron or queue workers using host local time.
- Frontend formatting UTC with a local formatter (or the reverse).
- DST boundaries for the user’s zone—not yours.
4. Prefer epoch or explicit offsets in logs
Human strings without offsets are ambiguous in multi-region systems. Log epoch milliseconds alongside a single UTC ISO string when debugging.