Set your dev machine to UTC — the cheap trick that found two nasty timezone bugs

I switched my laptop to UTC for development. It made scheduled jobs and date math failures obvious — and introduced calendar pain I didn't expect.

Written by: Arjun Malhotra

Laptop on a wooden table displaying code, with a small analog clock blurred in the background
Photo by Nick Morrison on Unsplash

The pager went off at 3:12 a.m. IST. A client in Europe reported onboarding emails arriving eight hours late. I pulled open the logs and everything looked fine — jobs succeeded, no retries, no queue backlogs. The timestamps were normal. Until I noticed the developer who wrote the job had their laptop set to IST, and the staging server was doing time math in UTC. A rounded-off timezone assumption hid the bug.

A week later I flipped my dev laptop to UTC and left it. No drama, just a new, glaringly honest clock in the top bar. Within days I had two bugs reproduced locally that otherwise had escaped for months.

Why I flipped my laptop to UTC

We ship globally but test mostly from Bengaluru and a single staging server in AWS London. On paper, everything used UTC; in practice, developers write code on machines set to IST and tests run with local defaults. That mismatch is a classic source of bugs — off-by-one-day emails, wrong “expires at” calculations, scheduled jobs firing at odd business hours.

Setting my laptop to UTC does three things for me:

How it found the bugs

Two concrete cases.

  1. The “midnight job” that skipped Mumbai users We had a nightly job that ran every day at “midnight local time” to generate daily digests. The job was implemented in Node, scheduled with a cron expression. On staging (UTC) it ran at 00:00 UTC and called a library that converted to local time using the server timezone. On my IST laptop set to local time, the job appeared to run at 00:00 and produce correct digests. After switching to UTC, I saw the job’s “local conversion” move the boundary and realized it was picking dates incorrectly for IST users — some users fell into the previous day. Rewriting the job to store and operate on dates in UTC and explicitly compute daily buckets for Asia/Kolkata fixed it. Tests followed.

  2. The token expiry that lived longer in dev An auth token had its expiry calculated using Date.toLocaleString in a couple of helper functions. On dev machines (IST) the expiry showed, say, 11:30 pm, but on servers (UTC) it showed 6:00 pm because of a messy mix of .getTimezoneOffset() use and implicit conversions. With my laptop in UTC I reproduced token-refresh failures locally within minutes instead of hunting logs at 2 a.m. The fix was boring: keep expiry in UTC across the stack and only format for display at the UI boundary.

How I survived the change (and the thing I broke)

Flipping to UTC is cheap and powerful, but not frictionless. I learned the hard way.

What broke

How I made it tolerable

The tradeoff I didn’t expect This uncovered a cultural issue in our team: because most of us are in IST, many PRs and tests didn’t consider other timezones. Exposing that required a small policy change — we now require at least one integration test that runs with TZ=UTC and another with TZ=Asia/Kolkata for any feature touching dates. It slowed down PRs a little. But it also stopped us shipping “works on my machine” bugs to production.

One limitation: flipping my laptop to UTC won’t magically fix libraries or third-party services that embed local-time assumptions. It will, however, make those assumptions visible sooner. For example, a vendor webhook that sends timestamps in local time still needs a contract and robust parsing on our side.

Takeaway If you work on anything that touches dates, set your dev machine to UTC for a week. You’ll either find bugs you didn’t know you had, or you’ll hate it and go back. Either way you’ll be more aware. I kept mine in UTC — the minor pain in scheduling is cheaper than shipping two bugs that only show up at midnight in Mumbai.