2

I am in Asia and I want to calculate the offset of Australia. I know how to calculate the value of the offset the code is written below:

var timezone_offset = new Date().getTimezoneOffset();

But how to calculate it for the other locations? Anyone can guide me??

Asma Ahmad
  • 408
  • 1
  • 3
  • 15
  • 1
    There is no such information provided to you by the browser. `Date` only gives you the timezone offset set by the system. Any other timezone that you need, **you** would have to provide to your code. Dealing with `Date`s, you should take a look at https://momentjs.com/ and in regard to this specific question, at the module https://momentjs.com/timezone/ – Thomas Jun 01 '20 at 11:50
  • 1
    We can't do it without any library? – Asma Ahmad Jun 01 '20 at 12:10

2 Answers2

4

While this can be done in a short function, it would be best to use a library as there are many quirks to overcome. The offset can be determined using the timezone options of toLocaleString or Intl.DateTimeFormat.

However, if the language used for formatting matches the language of the location, it returns the timezone abbreviation instead of the offset. To deal with that, the following function first uses English and if that returns the abbreviation rather than an offset, it uses French. English offsets start with GMT, French offsets start with UTC. Where the offset is +0, they return just "GMT" or "UTC".

It's been tested with all IANA locations listed by wikipedia and seems to work for all of them but it should be tested more widely. Also, there should be feature tests before attempting to run it (i.e. support for Int.DateTimeFormat constructor, formatToParts method and the timeZoneName option).

// Return offset on date for loc in ±H[:mm] format. Minutes only included if not zero
function getTimezoneOffset(date, loc) {
  // Try English to get offset. If get abbreviation, use French
  let offset;
  ['en','fr'].some(lang => {
    // Get parts - can't get just timeZoneName, must get one other part at least
    let parts = new Intl.DateTimeFormat(lang, {
      minute: 'numeric',
      timeZone: loc,
      timeZoneName:'short'
    }).formatToParts(date);
    // Get offset from parts
    let tzName = parts.filter(part => part.type == 'timeZoneName' && part.value);
    // timeZoneName starting with GMT or UTC is offset - keep and stop looping
    // Otherwise it's an abbreviation, keep looping
    if (/^(GMT|UTC)/.test(tzName[0].value)) {
      offset = tzName[0].value.replace(/GMT|UTC/,'') || '+0';
      return true;
    }
  });
  // Format offset as ±HH:mm
  // Normalise minus sign as ASCII minus (charCode 45)
  let sign = offset[0] == '\x2b'? '\x2b' : '\x2d';
  let [h, m] = offset.substring(1).split(':');
  return sign + h.padStart(2, '0') + ':' + (m || '00');
}

let d = new Date();
console.log('Current offset for following locations:');
['Australia/Yancowinna',
 'Australia/Lord_Howe',
 'Australia/Canberra',
 'Pacific/Honolulu',
 'Europe/London',
 'Canada/Eastern'
].forEach( loc =>
  console.log(loc + ': ' + getTimezoneOffset(d, loc))
);

I don't suggest you use this function, it's really to show how messy getting the offset for a specific location can be.

Note that Australia has a number of offsets and some places observe daylight saving and others don't.

RobG
  • 142,382
  • 31
  • 172
  • 209
0

The accepted answer is correct, but if you are fine with some of the timezones to appear without the percise offset, a shorter way that doesn't require string parsing / manipulation will be:

// Return offset on date for loc in ±H[:mm] format.
function getTimezoneOffset(date, loc) {
  return new Intl.DateTimeFormat('en-US', { timeZone: loc, timeZoneName: "shortOffset" })
    .formatToParts(date)
    .filter(e => e.type === "timeZoneName")[0].value
}

let d = new Date();
console.log('Current offset for following locations:');
['Australia/Yancowinna',
  'Australia/Lord_Howe',
  'Australia/Canberra',
  'Pacific/Honolulu',
  'Europe/London',
  'Canada/Eastern',
  'America/Los_Angeles',
  'Asia/Kolkata'
].forEach(loc =>
  console.log(loc + ': ' + getTimezoneOffset(d, loc))
);

You can see the the options for the timezone name format here [1]:

timeZoneName - The localized representation of the time zone name. Possible values are:

  • "long" Long localized form (e.g., Pacific Standard Time, Nordamerikanische Westküsten-Normalzeit)
  • "short" Short localized form (e.g.: PST, GMT-8)
  • "shortOffset" Short localized GMT format (e.g., GMT-8)
  • "longOffset" Long localized GMT format (e.g., GMT-0800)
  • "shortGeneric" Short generic non-location format (e.g.: PT, Los Angeles Zeit).
  • "longGeneric" Long generic non-location format (e.g.: Pacific Time, Nordamerikanische Westküstenzeit)

[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#syntax:~:text=timeZoneName,Nordamerikanische%20Westk%C3%BCstenzeit)

Michael
  • 22,196
  • 33
  • 132
  • 187