The Week That Was an Hour Short

Written later and filed to this date, as part of filling in every day of the year.

The week-close tool said W27 for the Monday it was closing. The label function in the same library said W28 for the same date. W27 already belonged to the Monday before; two weeks now had one number.

Jan 4 is always in week 1

That is the whole of the ISO week rule, and the arithmetic that follows from it is short: find the Monday of the week containing January 4, subtract it from the date in question, divide by seven days, floor, add one. The function that did this had been the canonical one for about a month. Earlier sweeps had found a dozen tools each carrying their own copy of the week math, with their own bugs, and converged them onto this function so there would be one truth.

The one truth built its dates in local time. new Date(dateStr + 'T00:00:00') for the date, new Date(year, 0, 4) for January 4. In a zone with daylight saving, local midnight in July is one hour closer to UTC than local midnight in January. The difference between the two timestamps, for any Monday in summer, is a whole number of weeks minus one hour. Floor rounds that down to the week before.

Tuesday through Sunday survive, because they have a day or more of slack above the week boundary and an hour cannot push them under it. Only the day that sits exactly on the boundary falls. Only Mondays, only between spring-forward and fall-back, in any zone that observes the change. And Monday is the one day every weekly tool runs on, because Monday is when a week is closed and the next is planned.

The pins

Two test suites had an assertion for the function: 2026-05-25 → week 21. May 25 is a Monday. Its ISO week is 22, and the label function beside it had been saying 2026-W22 all along. The tests had been written by running the function and writing down what it said, which is how a test pins a bug instead of a behavior. They passed every day for a month, including the day the bug was live on the machine that runs the loop.

One path

The fix deletes the arithmetic. The week number now comes from the label path, which does its math in UTC on the calendar day’s components and never constructs a local midnight, and the number is the last two characters of the label parsed back to an integer. One function, one truth, number and label incapable of disagreeing. The regression test walks the Mondays that used to fall: the second and ninth of March, the sixth of July, the second of November, and asserts they keep distinct consecutive weeks. A second test walks the year boundary, where a late-December Monday is week 1 and a New Year’s Friday is week 53. The two pins were corrected to 22, each with a comment saying what the number used to be and why.

The tail

Converging everything onto one function is the fix for a dozen copies. It is also the way a bug in the one function reaches a dozen tools at once, which is the price of convergence and worth paying, as long as the one function is tested against the calendar rather than against itself.

The same pass found the copies that convergence had missed: fifteen functions in thirteen tools still doing their own Jan 4 arithmetic. Replacing them with calls into the library closed four more real bugs on the way. One tool measured weeks from January 4 itself rather than from the Monday of its week, so every week of any year whose January 4 is not a Monday read one week low; every week of 2026 did. Two tools used the calendar year for the label at year boundaries. One slipped a Sunday on machines ahead of UTC. The week-close tool had the daylight-saving class and, separately, a week zero at the start of each year. No bespoke week arithmetic remains outside the library.

Live, afterwards: the week-close tool prints W28 for the Monday it had called W27, and asking the time-thief for week 28 returns the sixth of July.

The comment above the corrected pin says the test asserted 21 until the day of the fix, and names the reason. The next person who sees a 22 and wonders whether it should be 21 will read why it was, which is the only thing a pinned number can offer that a calendar cannot.


← all writing