Great work!

XP to next level

BugEater

Client-Server Timezone Mismatch

Learning Objectives

By the end of this lesson you will be able to:

  • Identify the three timezone contexts in a typical web application
  • Explain the "booking at midnight" bug caused by a UTC+12 user
  • Describe how a user entering December 31 at 11 PM can create a January 1 record in the database
  • Design a test strategy using extreme UTC offsets to expose timezone mismatch bugs

The Three-Timezone Problem

A typical web application involves at least three timezone contexts, each of which may differ from the others:

  1. Browser (client) timezone: The timezone the user's device is configured to use. This is what the user sees when they look at dates and times in the UI. JavaScript's Intl.DateTimeFormat or Date object uses this timezone by default.

  2. Server timezone: The timezone the application server runs in. In a well-designed system, this should be UTC. However, poorly configured servers may use the datacenter's local timezone (US Eastern, EU Central, etc.).

  3. Database timezone: The timezone the database connection uses for interpreting and storing timestamps. Ideally this is also UTC. Some database drivers or ORMs apply their own timezone conversion.

When these three contexts are not aligned, date and time values get transformed silently at each boundary crossing — browser to server, server to database, database to server, server to browser. The user sees dates that differ from what they entered.

The "Booking at Midnight" Bug

Consider a user in Auckland, New Zealand, which observes UTC+13 in summer. At 1:00 AM local time on January 2, the user books a hotel room for "today" — January 2.

Their browser sends the request. The booking date is determined one of two ways:

  • If the frontend sends local date "January 2" and the server interprets it as January 2 UTC: this appears correct — but only because the user is only 13 hours ahead, and the stored UTC date is January 1 (1:00 AM NZT = 12:00 PM January 1 UTC). The hotel system shows January 1 as the booking date.
  • If the frontend sends a UTC timestamp computed from the local time: 1:00 AM NZT on January 2 = 12:00 PM on January 1 UTC. The stored date is January 1 — the user's "yesterday" in UTC terms.

Either way, the booking appears on January 1 in the hotel's system even though the user intended January 2. The user calls the hotel, there is no room prepared, and neither party can easily diagnose the cause.

The December 31 to January 1 Shift

A related bug affects year boundaries. A user in Mumbai (UTC+05:30) enters a date of December 31 at 11:00 PM local time. The frontend converts this to UTC:

  • 11:00 PM IST on December 31 = 11:00 PM − 05:30 = 5:30 PM UTC on December 31

So far, so good. But if the server or database strips the time component and stores only the date portion in UTC, the stored date is December 31 — correct.

However, consider a user in Tehran (UTC+03:30) entering the same date at 11:00 PM local time: 11:00 PM − 03:30 = 7:30 PM UTC on December 31. Still correct.

Now consider a user in Honolulu (UTC-10:00) entering December 31 at 11:00 PM local time: 11:00 PM + 10:00 = 9:00 AM UTC on January 1 of the following year. The stored date is January 1 — the user's intended December 31 became January 1 in the system. For a financial year-end report, a legal filing deadline, or a seasonal promotion, this one-day shift is a serious defect.

Test Strategy: Use Extreme UTC Offsets

The most effective way to expose client-server timezone mismatch bugs is to test from extreme timezone positions:

UTC+14 (Pacific/Kiritimati — Christmas Island): The farthest timezone ahead of UTC. A user here is always at least 14 hours into "tomorrow" relative to UTC. Any date entered by this user in the evening will likely translate to the next UTC date. Test: user in UTC+14 enters today's date at 11 PM; verify the stored date matches the user's local date.

UTC-12 (Pacific/Baker Island): The farthest timezone behind UTC. Test: user in UTC-12 enters a date at 1 AM; verify the stored date matches the user's local date, not yesterday's UTC date.

UTC+13 (Pacific/Auckland in summer): A commonly inhabited far-ahead timezone. Test midnight bookings as described above.

UTC+05:30 (Asia/Kolkata): A half-hour offset that tests systems which only handle whole-hour offsets.

For each test:

  1. Set the browser or test client's timezone to the target offset.
  2. Perform a date-sensitive action (create booking, submit form, log an event).
  3. Read back the stored date via API.
  4. Compare the stored date to the user's intended local date.

Any mismatch confirms a client-server timezone bug. Log the user's timezone, the submitted value, and the stored value as evidence.

Quiz

How many different timezone contexts are typically involved in a web booking application?

What bug occurs when a user in UTC+12 books a hotel room for "today" at 11 PM their local time?

Which timezone should API requests use when sending datetime values to a server?

How can you expose a client-server timezone mismatch bug most effectively?