Jeff Thoensen

A test checking that a scheduled reminder appeared on the right day passed every time I ran it on my machine and failed every time it ran in CI, with nothing about the code or the test itself different between the two runs. The only thing that was different was the timezone the two machines were running in.

My machine was set to Eastern time, during the part of the year when Eastern runs four hours behind UTC. The CI runner ran in UTC. The test scheduled a reminder for 11 PM on a given day and checked that it showed up under that same calendar date. At 11 PM Eastern, the date comparison ran fine, because the reminder and the check were both being read in the same local time. Four hours ahead in UTC, 11 PM Eastern is already 3 AM the next day, so the reminder that should have shown up "today" was landing on tomorrow instead, and the test correctly failed against a real bug in how the date was being compared.

The bug lived in the feature: the reminder was meant to fire at one specific scheduled instant, not sometime across the user's local calendar day, so comparing it against "today" only makes sense once both sides are read in the same timezone. Comparing a reminder's timestamp against today without ever converting both to a common timezone first happens to work by accident whenever the two machines involved share the same offset from UTC, and stops working the moment they don't.

I fixed the comparison by converting both sides to UTC before comparing, since the reminder represents one fixed instant rather than a day tied to whoever happens to be looking at it. If the feature had actually meant "today on the user's own calendar," converting to UTC would have been the wrong fix, since two users in different timezones can disagree about what day a given instant falls on, and the right move there would have been converting both sides into the user's local timezone instead. Getting that distinction right mattered more than which timezone I ended up picking.

I also set CI to run in a timezone deliberately different from wherever tests get run manually, so a mismatch like this fails immediately instead of waiting for whichever engineer's laptop happens to be in a different zone than the pipeline.

The habit worth keeping from this: any test involving dates is also, whether anyone intended it or not, a test of timezone handling. Code that only works because two clocks happen to agree is running on coincidence, and the only way to find that out before a user does is making sure your test environment doesn't coincidentally match your dev machine's timezone.