Kamero

How to Detect User Timezone in JavaScript (3 Methods Compared)

Displaying times in the wrong timezone is a surprisingly common UX problem. Meeting schedulers, event platforms, dashboards, and notification systems all need to know the user's timezone. Here are three ways to detect it, with tradeoffs for each.

Method 1: Intl API (Client-Side)

The simplest and most reliable client-side approach:

const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(timezone); // "America/New_York"

Pros:

Cons:

Method 2: IP Geolocation (Server or Client)

Get the timezone from the user's IP address:

const { timezone } = await fetch(
  "https://geo.kamero.ai/api/geo"
).then(r => r.json());

console.log(timezone); // "America/New_York"

Pros:

Cons:

Method 3: Date UTC Offset

The old-school approach using the Date object:

const offsetMinutes = new Date().getTimezoneOffset();
const offsetHours = -offsetMinutes / 60;
console.log(`UTC${offsetHours >= 0 ? "+" : ""}${offsetHours}`);
// "UTC-5"

Pros:

Cons:

Which Method Should You Use?

ScenarioBest MethodWhy
Display local time in UIIntl APIInstant, accurate, no network
Server-side renderingIP GeolocationOnly option on the server
Email schedulingIP GeolocationNeed timezone before user interacts
Analytics / loggingIP GeolocationWorks server-side, gives extra data
Calendar / meeting appIntl API + user confirmationHighest accuracy, user can correct
Fallback / legacyDate offsetLast resort when nothing else works

Combining Methods for Best Results

The most robust approach uses the Intl API as the primary source and IP geolocation as a fallback or server-side complement:

async function detectTimezone() {
  // Try Intl API first (client-side only)
  if (typeof window !== "undefined") {
    const intlTz = Intl.DateTimeFormat().resolvedOptions().timeZone;
    if (intlTz) return intlTz;
  }

  // Fallback to IP geolocation (works anywhere)
  try {
    const { timezone } = await fetch(
      "https://geo.kamero.ai/api/geo"
    ).then(r => r.json());
    return timezone || "UTC";
  } catch {
    return "UTC";
  }
}

// Usage
const tz = await detectTimezone();
const now = new Date().toLocaleString("en-US", {
  timeZone: tz,
  dateStyle: "full",
  timeStyle: "short",
});

Practical Example: Show Event Times Locally

async function formatEventTime(utcTime: string) {
  const tz = await detectTimezone();
  const date = new Date(utcTime);

  return {
    local: date.toLocaleString("en-US", {
      timeZone: tz,
      dateStyle: "medium",
      timeStyle: "short",
    }),
    timezone: tz,
    offset: date.toLocaleString("en-US", {
      timeZone: tz,
      timeZoneName: "short",
    }).split(" ").pop(),
  };
}

const event = await formatEventTime("2026-03-15T18:00:00Z");
// { local: "Mar 15, 2026, 1:00 PM", timezone: "America/New_York", offset: "EST" }

Get Timezone from IP

The Kamero API returns IANA timezone with every request. No key needed.

View Documentation โ†’