Skip to content

JavaScript Tutorial Dates and Time

JavaScript Time Zones and UTC

Lesson 92 of 258 2 min read By Deepak Paswan Updated Oct 4, 2026

Time zones are the biggest source of date bugs, because the same moment has different clock times in different places.

Two things that are different

  • A moment in time is the same for everybody. A Date stores exactly that: a timestamp.
  • A clock reading (“10:30 on 15 March”) depends on the time zone.

A Date object has no time zone of its own. Whenever you read parts of it or print it, JavaScript turns the moment into a clock reading using either UTC or the visitor’s local zone.

script.js
JS
const moment = new Date("2026-03-15T23:30:00Z");

console.log(moment.getUTCDate()); // → 15   (UTC reading)
// moment.getDate() could be 15 or 16, depending on where the user is

At 23:30 UTC, it is already tomorrow in Tokyo or Sydney. That is how “off by one day” bugs happen.

UTC

UTC (Coordinated Universal Time) is the shared reference with no daylight saving. "Z" at the end of an ISO string means UTC.

Rules that prevent most problems

  1. Store and send timestamps in UTC, preferably ISO strings (toISOString()) or numbers.
  2. Convert to local time only when you display it, with toLocaleString, Intl.DateTimeFormat or the local getters.
  3. Be careful with date-only values such as birthdays and holidays. They have no time and no zone, but new Date("2026-03-15") is UTC midnight, which can display as the previous day in the Americas.
script.js
JS
const birthday = new Date("2026-03-15");   // UTC midnight

console.log(birthday.toLocaleDateString("en-US", { timeZone: "UTC" }));              // → 3/15/2026
console.log(birthday.toLocaleDateString("en-US", { timeZone: "America/Los_Angeles" })); // → 3/14/2026

The second line is the same moment shown in Los Angeles, where it is still the 14th. For a date-only value, display it with timeZone: "UTC", as in the first line, so it never shifts.

Seeing the visitor’s zone

script.js
JS
const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(typeof zone); // → string

The result is a name such as Asia/Kolkata.

Daylight saving time

Clocks jump in spring and fall in many places, so local days can be 23 or 25 hours long, and some local times do not exist or happen twice. Doing arithmetic in UTC avoids it, and the Intl formatters apply the correct rules for display.

dangerous
Do not compute with time zone offsets by hand
getTimezoneOffset() is the offset right now, and offsets change with daylight saving. Avoid subtracting it manually. Let Intl do the conversion.