Debugging remote timezone issues with Chrome DevTools MCP

A US-based client opened a ticket: the travel itinerary showed February 26th instead of February 27th for a Rome-to-Milan transfer. One day off. In travel, that's a stranded passenger.
I debugged the whole thing from VS Code using Chrome DevTools MCP, which lets an AI agent control Chrome's debugging tools (network inspection, console, DOM) through the Model Context Protocol. Instead of manually toggling Chrome's timezone settings and reloading four times, I had the agent run timezone simulations in the browser console, inspect the network payload, and verify the fix. One editor session, start to finish.
The bug
The client in New York saw this:
| Field | Expected | What they saw |
|---|---|---|
| Pick up | 27/02/2026, Rome | 26/02/2026, Rome |
| Drop off | 27/02/2026, Milan | 26/02/2026, Milan |
The dates were exactly one day off, both of them. Not random corruption, not a calculation error. A one-day shift that's consistent across fields smells like a timezone conversion that shouldn't be there. From my machine in Rome (UTC+1), everything looked correct, which made it worse. I needed to see what the client was actually seeing.
Reproducing the bug with MCP
The traditional approach to timezone bugs: open Chrome DevTools, change the timezone in sensor overrides, reload, inspect. Repeat for each timezone. Slow, tedious, easy to mess up.
Instead, I had the MCP agent run a simulation directly in the browser console, testing how the frontend's date code behaves across four timezones at once:
const serverDate = "2026-02-27"
const parsed = new Date(serverDate)
const timezones = ["Europe/Rome", "America/New_York", "America/Los_Angeles", "Asia/Tokyo"]
const results = {}
timezones.forEach((tz) => {
results[tz] = parsed.toLocaleDateString("it-IT", { timeZone: tz })
})
| Timezone | Displayed date | Correct? |
|---|---|---|
| Europe/Rome | 27/02/2026 | ✓ |
| America/New_York | 26/02/2026 | ✗ |
| America/Los_Angeles | 26/02/2026 | ✗ |
| Asia/Tokyo | 27/02/2026 | ✓ |
Bug confirmed. Any negative UTC offset shows the previous day.
Tracing the data
MCP's network inspection showed what the server was sending:
{
"start_date": "2026-02-27",
"end_date": "2026-02-27",
"origin": { "name": "Rome" },
"destination": { "name": "Milan" }
}
Plain YYYY-MM-DD strings. No time component, no timezone offset. Just a calendar date. The server was fine.
The root cause
The Vue component that renders the date:
const formattedPickupDateTime = computed(() => {
const date = new Date(props.pickupDate)
const formatted = date.toLocaleDateString("it-IT")
return { date: formatted, time }
})
There it is. new Date('2026-02-27') parses the string as UTC midnight. Then toLocaleDateString converts to the user's local timezone.
In Rome (UTC+1): midnight UTC becomes 1:00 AM on the 27th. Correct. In New York (UTC-5): midnight UTC becomes 7:00 PM on the 26th. Wrong.
The Date constructor was the trap. The string "2026-02-27" looks harmless, but once it enters JavaScript's Date system, it picks up timezone semantics nobody intended.
The fix
The server sends calendar dates: a day on a calendar, not a moment in time. The fix was to stop treating them as moments:
function dateToString(dateString: string): string {
if (!dateString) return ""
const cleanDateString = dateString.substring(0, 10)
const [year, month, day] = cleanDateString.split("-")
return `${day}/${month}/${year}`
}
Updated component:
const formattedPickupDateTime = computed(() => {
const date = dateToString(props.pickupDate)
return { date, time }
})
No new Date(). The string "2026-02-27" gets split on hyphens and rearranged into "27/02/2026". Same output in Tokyo, Rome, and New York.
After deploying, I used MCP again: the same simulation that found the bug now confirmed the fix. Four timezones, all showing 27/02/2026, no Chrome settings changed.
Locking it down with tests
If anyone refactors dateToString to use Date objects later, these tests should catch it:
import { describe, it, expect } from "vitest"
import dateToString from "@/utils/dateToString"
describe("dateToString", () => {
it("reformats YYYY-MM-DD to DD/MM/YYYY", () => {
expect(dateToString("2026-02-27")).toBe("27/02/2026")
})
it("returns empty string for falsy input", () => {
expect(dateToString("")).toBe("")
})
it("handles date strings with time components", () => {
expect(dateToString("2026-02-27T23:00:00Z")).toBe("27/02/2026")
expect(dateToString("2026-02-27T00:00:00+01:00")).toBe("27/02/2026")
})
})
The tests above verify correctness, but they won't catch a timezone regression. If someone refactors dateToString to use new Date(), the tests still pass on any machine where the local timezone has a positive UTC offset. They'd only fail in CI if the runner happens to be in a negative-offset timezone.
To actually catch that, the standard way in a Node.js environment like Vitest is to set the TZ environment variable. In modern Node.js versions, you can even switch timezones dynamically between tests:
import { it, expect } from "vitest"
it.each([
{ tz: "America/New_York", expected: "26/02/2026" },
{ tz: "Europe/Rome", expected: "27/02/2026" },
{ tz: "Asia/Tokyo", expected: "27/02/2026" },
] as const)("produces $expected when TZ=$tz", ({ tz, expected }) => {
process.env.TZ = tz
expect(dateToString("2026-02-27")).toBe(expected)
})
(Note: While Node.js 22+ handles process.env.TZ changes dynamically, in older versions the timezone was cached after the first Date was created. If you are on an older stack, you might need to run separate test processes or set the timezone at the very top of the file.)
Why this catches everyone
new Date('2026-02-27') parses as UTC midnight: 2026-02-27T00:00:00.000Z. This is per ECMA-262 §21.4.3.2: date-only strings are interpreted as UTC.
Meanwhile, new Date(2026, 1, 27) creates a date in the local timezone. Two constructors, two different timezone behaviors. I've known this for years and still almost missed it.
The original code was written and tested in Rome. UTC midnight is 1:00 AM in Rome, still on the 27th, so the bug was invisible during development. It only surfaces in negative-UTC timezones, where midnight UTC falls on the previous calendar day. I develop in Rome. Of course I didn't see it.
What I took away
If you're displaying a calendar date, don't put it through Date. Split the string, rearrange, render. But document why. The next developer will look at dateToString and think "why didn't they just use toLocaleDateString?" The comment is part of the answer. The timezone-mock tests are the rest: they show exactly what breaks if someone swaps in new Date().
Timezone bugs are invisible from positive-UTC locations. UTC midnight is still the right calendar day in Western Europe and East Asia. The bug only shows up in the Americas.
Chrome DevTools MCP collapses the debugging loop. The traditional timezone-toggle routine takes minutes of clicking around per cycle. The agent tested four timezones in one console evaluation, then the same simulation verified the fix. The debugging context stayed in one place instead of splitting across browser tabs, terminals, and my head.
Debugged with Chrome DevTools MCP, Vue 3 and Nuxt 4, and a healthy suspicion of new Date().