Backend · TypeScript, Node.js
The timezone bug that judged people unfairly
The problem
The system judges each salesperson's week: did they hit their calling target between Monday and Sunday? Miss it, and a case is raised with their manager. That verdict affects someone's standing at work, so the week boundary has to be exactly right.
What failed first
I shipped the bug myself. My first version used the server's local date maths: build a date, set the time to midnight. It worked perfectly, because the server was in India.
On a server running in UTC, the Monday-to-Sunday window slides by five and a half hours. Work logged on Sunday evening, the end-of-week push the verdict exists to count, lands in the wrong week. The person did the work, and the system says they didn't.
The trap worth knowing: setting the scheduled job's timezone does not fix this. The job's timezone decides when it runs. It does nothing about which week a timestamp falls into. Those are two different problems that look like one.
The decision
Week boundaries are computed as exact instants in the organisation's own timezone, using offsets read from the Intl API.
- The week ends at its own local midnight, never at start plus seven times 24 hours. Across a daylight-saving change, a week is 167 or 169 hours long.
- The offset is read twice. The first guess can land on the wrong side of a daylight-saving change, so the code re-reads the offset at the corrected instant.
- India has no daylight saving. I built for it anyway, because the organisation's timezone is configurable and "works in India" is not a specification.
// How far `timeZone` is ahead of UTC at a given instant, in milliseconds.
function offsetAt(instant: number, timeZone: string): number {
const parts = new Intl.DateTimeFormat("en-US", {
timeZone,
hourCycle: "h23",
year: "numeric", month: "2-digit", day: "2-digit",
hour: "2-digit", minute: "2-digit", second: "2-digit",
}).formatToParts(instant);
const part = (type: string) => Number(parts.find((p) => p.type === type)?.value);
const wall = Date.UTC(part("year"), part("month") - 1, part("day"),
part("hour"), part("minute"), part("second"));
return wall - (instant - (instant % 1000));
}
// The UTC instant of local midnight on a calendar date in `timeZone`.
export function zonedMidnight(year: number, month: number, day: number, timeZone: string) {
const wall = Date.UTC(year, month - 1, day);
const guess = wall - offsetAt(wall, timeZone); // first guess
return wall - offsetAt(guess, timeZone); // re-read the offset where we landed
}
The fairness rule sits on top: the system only judges a week once it is completely over in the organisation's timezone, so someone on a Monday-to-Saturday schedule can still catch up on Sunday.
The result
The module has no imports at all, on purpose, so its tests run on their own without starting the application. The same suite runs under TZ=UTC, TZ=Asia/Kolkata and TZ=America/New_York, and all three runs must produce identical results. Not similar. Identical.
When your code judges people, "works on my server" is not a passing grade.