Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Do I calculate the difference of 2 time zones in JavaScript?

For example, the difference in Eastern and Central is 1. My solution below feels hacky. Is there a easier / better way?

var diff = (parseInt(moment().tz("America/New_York").format("ZZ")) - parseInt(moment().tz("America/Chicago").format("ZZ"))) / 100;

My example is using the Momentjs library.

like image 483
Homer Avatar asked Mar 25 '15 20:03

Homer


People also ask

How do you find the time difference between two time zones?

Calculating time zones is simple and involves adding or subtracting an hour for every 15 degrees of longitude.

How does JavaScript handle different time zones?

The JavaScript getTimezoneOffset() method is used to find the timezone offset. It returns the timezone difference in minutes, between the UTC and the current local time. If the returned value is positive, local timezone is behind the UTC and if it is negative, the local timezone if ahead of UTC.

What is a timezone difference?

Time zones and time differences There are time differences around the world based on “Coordinated Universal Time (UTC).” There are 24 regions (Time Zones) around the world with a time difference of one hour. This system has been adopted internationally by setting the total time difference around the world as 24 hours.


2 Answers

It's impossible to calculate the difference between two arbitrary time zones. You can only calculate a difference for a specific moment in time.

  • It's currently 4 hours difference between London and New York (writing this on Mar 25, 2015).
  • But it was 5 hours difference a few weeks ago, and it will be 5 a few weeks from now.
  • Each time zone switches offsets for daylight saving time at a different point in time.

This is true in the general case between two time zones. However some time zones either switch exactly at the same time, or don't switch at all.

  • There is always one hour between London and Paris, because they switch at the same moment in time.
  • There are always 3 hours between Arizona and Hawaii, because neither have DST.

Keep in mind that in the United States, each time zone that uses DST actually switches at a different moment in time. They all switch at 2:00 AM in their local time, but not at the same universal moment in time.

  • So between Chicago and New York, there is usually 1 hour apart
  • But for two brief periods each year they are either 2 hours apart, or have the same exact time.

See also "Time Zone != Offset" in the timezone tag wiki.

Now with regard to moment-timezone, you said in comments:

The web server is in the Eastern time zone; we're in Central. I need the difference in the user's timezone and the server.

The time zone of the web server is irrelevant. You should be able to host from anywhere in the world without affecting your application. If you can't, then you're doing it wrong.

You can get the current time difference between your time zone (US Central time) and the user's. You don't even need to know the user's exact time zone for this, if the code is running in the browser:

var now = moment();
var localOffset = now.utcOffset();
now.tz("America/Chicago"); // your time zone, not necessarily the server's
var centralOffset = now.utcOffset();
var diffInMinutes = localOffset - centralOffset;

If instead the code was running on the server (in a node.js app), then you would need to know the user's time zone. Just change the first line like this:

var now = moment.tz("America/New_York"); // their time zone

Updated answer:

This can be done without Moment, in environments that support the ECMAScript Internationalization API and have fully implemented IANA time zone support. This is most browsers these days.

function getTimeZoneOffset(date, timeZone) {

  // Abuse the Intl API to get a local ISO 8601 string for a given time zone.
  let iso = date.toLocaleString('en-CA', { timeZone, hour12: false }).replace(', ', 'T');

  // Include the milliseconds from the original timestamp
  iso += '.' + date.getMilliseconds().toString().padStart(3, '0');

  // Lie to the Date object constructor that it's a UTC time.
  const lie = new Date(iso + 'Z');

  // Return the difference in timestamps, as minutes
  // Positive values are West of GMT, opposite of ISO 8601
  // this matches the output of `Date.getTimeZoneOffset`
  return -(lie - date) / 60 / 1000;
}

Example usage:

getTimeZoneOffset(new Date(2020, 3, 13), 'America/New_York') //=> 240
getTimeZoneOffset(new Date(2020, 3, 13), 'Asia/Shanghai') //=> -480

If you want the difference between them, you can simply subtract the results.

Node.js

The above function works in Node.js where the full-icu internationalization support is installed (which is the default for Node 13 and newer). If you have an older version with either system-icu or small-icu, you can use this modified function. It will work in browsers and full-icu environments also, but is a bit larger. (I have tested this on Node 8.17.0 on Linux, and Node 12.13.1 on Windows.)

function getTimeZoneOffset(date, timeZone) {

  // Abuse the Intl API to get a local ISO 8601 string for a given time zone.
  const options = {timeZone, calendar: 'iso8601', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false};
  const dateTimeFormat = new Intl.DateTimeFormat(undefined, options);
  const parts = dateTimeFormat.formatToParts(date);
  const map = new Map(parts.map(x => [x.type, x.value]));
  const year = map.get('year');
  const month = map.get('month');
  const day = map.get('day');
  const hour = map.get('hour');
  const minute = map.get('minute');
  const second = map.get('second');
  const ms = date.getMilliseconds().toString().padStart(3, '0');
  const iso = `${year}-${month}-${day}T${hour}:${minute}:${second}.${ms}`;

  // Lie to the Date object constructor that it's a UTC time.
  const lie = new Date(iso + 'Z');

  // Return the difference in timestamps, as minutes
  // Positive values are West of GMT, opposite of ISO 8601
  // this matches the output of `Date.getTimeZoneOffset`
  return -(lie - date) / 60 / 1000;
}

Note that either way, we must go through Intl to have the time zone applied properly.

like image 110
Matt Johnson-Pint Avatar answered Oct 26 '22 18:10

Matt Johnson-Pint


The difference between two timezones can only be measured w.r.t particular time because of things like Daylight saving time (dst).

But, for a particular date, below code should work.

function getOffsetBetweenTimezonesForDate(date, timezone1, timezone2) {
  const timezone1Date = convertDateToAnotherTimeZone(date, timezone1);
  const timezone2Date = convertDateToAnotherTimeZone(date, timezone2);
  return timezone1Date.getTime() - timezone2Date.getTime();
}

function convertDateToAnotherTimeZone(date, timezone) {
  const dateString = date.toLocaleString('en-US', {
    timeZone: timezone
  });
  return new Date(dateString);
}

The offset/difference is in milli sec

Then all you have to do is:

const offset = getOffsetBetweenTimezonesForDate(date, 'America/New_York', 'America/Chicago');
like image 22
shub_shah Avatar answered Oct 26 '22 18:10

shub_shah