All posts

The Hidden Timezone Problem in Node.js & Express (And How I Solved It)

When building full-stack applications, time handling often seems simple at first. But once your application deals with users in different locations, timezones become a real challenge.

While building one of my projects using Node.js and Express, I encountered a confusing issue related to server time, local time, and timezone conversion. This blog explains the problem I faced and the solution that worked best.

The Problem

In my Express server, I was storing timestamps using JavaScript's default time handling.

Example:

const createdAt = new Date();

At first glance this looks fine. But when I started converting this time into different timezones on the client side, things became inconsistent.

Sometimes the time would appear a few hours ahead or behind depending on where the server was running.

The issue happened because:

  • The server timezone
  • The user's local timezone
  • The stored timestamp format

were not aligned.

Another complication was that sometimes the time appeared as a string, which made timezone conversions even more difficult.

Why This Happens

JavaScript Date objects internally store time in UTC, but when we display them, they often convert to the local timezone automatically.

For example:

const date = new Date();
console.log(date);

The output depends on the environment where the code runs.

If the server is hosted in a different region, the timezone offset can create inconsistencies when sending data to the frontend.

The Real Issue: String Dates

At one point, the timestamp coming from the server looked like this:

"2024-05-12T10:30:00.000Z"

While this is technically an ISO string, many developers accidentally treat it like a simple string rather than converting it back to a Date object.

Without proper conversion, timezone calculations become unreliable.

The Solution I Used

The best approach I found was to follow three simple rules:

1. Always Store Time in UTC

On the server, store timestamps using UTC format.

const createdAt = new Date().toISOString();

This ensures the stored time is consistent globally.

2. Convert Time on the Client Side

Instead of converting time on the server, convert it based on the user's location in the frontend.

Example:

const localTime = new Date(serverTime).toLocaleString();

This automatically converts UTC to the user's local timezone.

3. Use a Reliable Time Library

Native JavaScript date handling can be confusing. Libraries like Day.js or Luxon make timezone handling much easier.

Example using Day.js:

import dayjs from "dayjs";

const localTime = dayjs(serverTime).format("YYYY-MM-DD HH:mm:ss");

These libraries provide clearer APIs for formatting and timezone conversion.

Best Practices for Handling Time in Web Apps

From my experience, these rules help avoid most timezone problems:

  1. Store time in UTC on the server
  2. Convert time to local timezone in the frontend
  3. Use ISO 8601 format for timestamps
  4. Use a dedicated date library for complex cases

Final Thoughts

Timezone bugs are subtle and easy to overlook during development, especially when the developer and server are in the same region.

But once an application has users across multiple locations, incorrect time handling can cause confusing user experiences.

The lesson I learned is simple: Always treat time as UTC on the backend and convert it only when displaying it to the user.