Calculate the UTC offset given a TimeZone string in JavaScript

Viewed 16912

Using the standard JS library (ECMA5), without using momentjs or external libs, how do you calculate the UTC offset given a TimeZone string such as "Europe/Rome" or "America/Los_Angeles"?

UTC Offsets may depend on whether it is DST or not, so it would make sense if the solution required converting the local client date to the specified Timezone String. The goal is just to know the offset from UTC.

function getUtcOffset(timezone) {
  // return int value. 
  // > 0 if +GMT 
  // < 0 if -GMT.
}
5 Answers

Youve got to:

  • get the current datetime (will give you the datetime in the current timezone of the current device)
  • get the current timezone offset
  • convert the datetime to the new/required timezone
  • get the difference between the current datetime and the converted datetime
  • add said difference to the current timezone offset

Eg returning timezone in hours:

function getTimezoneOffset(tz, hereDate) {
    hereDate = new Date(hereDate || Date.now());
    hereDate.setMilliseconds(0); // for nice rounding
    
    const
    hereOffsetHrs = hereDate.getTimezoneOffset() / 60 * -1,
    thereLocaleStr = hereDate.toLocaleString('en-US', {timeZone: tz}),
    thereDate = new Date(thereLocaleStr),
    diffHrs = (thereDate.getTime() - hereDate.getTime()) / 1000 / 60 / 60,
    thereOffsetHrs = hereOffsetHrs + diffHrs;

    console.log(tz, thereDate, 'UTC'+(thereOffsetHrs < 0 ? '' : '+')+thereOffsetHrs);
    return thereOffsetHrs;
}


getTimezoneOffset('America/New_York', new Date(2016, 0, 1));
getTimezoneOffset('America/New_York', new Date(2016, 6, 1));
getTimezoneOffset('Europe/Paris', new Date(2016, 0, 1));
getTimezoneOffset('Europe/Paris', new Date(2016, 6, 1));
getTimezoneOffset('Australia/Sydney', new Date(2016, 0, 1));
getTimezoneOffset('Australia/Sydney', new Date(2016, 6, 1));
getTimezoneOffset('Australia/Sydney');
getTimezoneOffset('Australia/Adelaide');

Which outputs like

America/New_York 2015-12-30T22:00:00.000Z UTC-5
America/New_York 2016-06-30T01:00:00.000Z UTC-4
Europe/Paris 2015-12-31T04:00:00.000Z UTC+1
Europe/Paris 2016-06-30T07:00:00.000Z UTC+2
Australia/Sydney 2015-12-31T14:00:00.000Z UTC+11
Australia/Sydney 2016-06-30T15:00:00.000Z UTC+10
Australia/Sydney 2019-08-14T03:04:21.000Z UTC+10
Australia/Adelaide 2019-08-14T02:34:21.000Z UTC+9.5

The chosen answer doesn't really answer the question. What the author want is a function that can input a timezone name and then return an offset.

After some investigations and digging the source code of icu4c, turns out the follow snippet can do what you need:

const getUtcOffset = (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(getUtcOffset("US/Eastern"));
console.log(getUtcOffset("Atlantic/Reykjavik"));
console.log(getUtcOffset("Asia/Tokyo"));

Note that the locale ia used here is Interlingua. The reason is that according to the source code of icu4c, the timezone name differs per locale. Even you use the same locale, the format of the timezone name can still vary based on different timezone.

With Interlingua (ia), the format is always the same pattern like GMT+NN:NN which can be easily parsed.

It's a little tircy but it works well in my own products.

Hope it helps you as well :)

For others who may land on this question, there is a method available on the standard Date function in JavaScript to get the offset from UTC called getTimezoneOffset.

Usage is simply (for example): new Date().getTimezoneOffset(). This returns the number of minutes the current timezone is from UTC. NOTE: It returns a negative number if the current timezone is ahead of UTC. For example, if the user's timezone is UTC+1, -60 is returned.

Related