'Get utc offset from timezone in Javascript

I need a Javascript function that given a timezone, returns the current utc offset.

For example, theFuncIneed('US/Eastern') -> 240

Any idea?

Thanks



Solution 1:[1]

In general, this is not possible.

  • US/Eastern is an identifier for a time zone. (It's actually an alias to America/New_York, which is the real identifier.)

  • 240 is a time zone offset. It's more commonly written as -04:00 (Invert the sign, divide by 60).

  • The US Eastern Time Zone is comprised of both Eastern Standard Time, which has the offset of -05:00 and Eastern Daylight Time, which has the offset of -04:00.

So it is not at all accurate to say US/Eastern = 240. Please read the timezone tag wiki, especially the section titled "Time Zone != Offset".

Now you did ask for the current offset, which is possible. If you supply a date+time reference, then you can resolve this.

  • For the local time zone of the computer where the javascript code is executing, this is built in with .getTimeZoneOffset() from any instance of a Date object.

  • But if you want it for a specific time zone, then you will need to use one of the libraries I listed here.

Solution 2:[2]

Following function can be used to return the UTC offset given a timezone:

const getTimezoneOffset = (timeZone, date = new Date()) => {
  const tz = date.toLocaleString("en", {timeZone, timeStyle: "long"}).split(" ").slice(-1)[0];
  const dateString = date.toString();
  const offset = Date.parse(`${dateString} UTC`) - Date.parse(`${dateString} ${tz}`);
  
  // return UTC offset in millis
  return offset;
}

It can be used like:

const offset = getTimezoneOffset("Europe/London");
console.log(offset);
// expected output => 3600000

Solution 3:[3]

It has become possible nowaday with Intl API:

The implementation of Intl is based on icu4c. If you dig the source code, you'll find that timezone name differs per locale, for example:

for (const locale of ["ja", "en", "fr"]) {
  const timeZoneName = Intl.DateTimeFormat(locale, {
    timeZoneName: "short",
    timeZone: "Asia/Tokyo",
  })
    .formatToParts()
    .find((i) => i.type === "timeZoneName").value;
  console.log(timeZoneName);
}

Fortunately, there is a locale, Interlingua (the langauge tag is ia), which uses the same pattern (ex. GMT+11:00) for timezone names.

The snippet below can meed your need:

const getOffset = (timeZone) => {
  const timeZoneName = Intl.DateTimeFormat("ia", {
    timeZoneName: "short",
    timeZone,
  })
    .formatToParts()
    .find((i) => i.type === "timeZoneName").value;
  const offset = timeZoneName.slice(3);
  if (!offset) return 0;

  const matchData = offset.match(/([+-])(\d+)(?::(\d+))?/);
  if (!matchData) throw `cannot parse timezone name: ${timeZoneName}`;

  const [, sign, hour, minute] = matchData;
  let result = parseInt(hour) * 60;
  if (sign === "+") result *= -1;
  if (minute) result += parseInt(minute);

  return result;
};

console.log(getOffset("US/Eastern")); // 240
console.log(getOffset("Atlantic/Reykjavik")); // 0
console.log(getOffset("Asia/Tokyo")); // -540

This way can be a little tricky but it works well in my production project. I hope it helps you too :)

Update

Many thanks to Bort for pointing out the typo. I have corrected the snippet.

Solution 4:[4]

You can do this using moment.js

moment.tz('timezone name').utcOffset()

Although this involves using moment-timezone.js

Solution 5:[5]

The answer of @ranjan_purbey results in NaN for me and the answer of @Weihang Jian throws an exception in Chrome (but works in Firefox).

Therefore, based on all the answers I came up with the following function which is basically a combination of both answers working together successfully for me:

const getTimeZoneOffset(timeZone) {
    const date = new Date().toLocaleString('en', {timeZone, timeZoneName: 'short'}).split(' ');
    const timeZoneName = date[date.length - 1];
    const offset = timeZoneName.slice(3);
    if (!offset) {
      return 0;
    }
    const matchData = offset.match(/([+-])(\d+)(?::(\d+))?/);
    if (!matchData) {
      throw new Error(`Cannot parse timezone name: ${timeZoneName}`);
    }
    const [, sign, hour, minute] = matchData;
    let result = parseInt(hour, 10) * 60;
    if (sign === '+') {
      result *= -1;
    }
    if (minute) {
      result += parseInt(minute, 10);
    }
    return result;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 ranjan_purbey
Solution 3 kleinfreund
Solution 4
Solution 5 dude