admin管理员组

文章数量:1288078

I am attempting to find a user-friendly list of time zones for users to select their current time zone. It would have mon names that time zones that are referred to such as Pacific Time (US and Canada).

This list should map the text to an IANA standard name such as America/Los_Angeles.

It would also remove listings that the user thinks of as the "same" time zone. For example the listing for Pacific Time (US and Canada) would correspond to America/Los_Angeles and America/Tijuana, which are the "same" time.

I've tried looking in the IANA Time Zone Database, ECMA Script internationalization API, and libraries like Moment.js. They can parse the IANA name into the mon name, for example America/Los_Angeles ==> "Pacific Standard Time" but don't have a built-in function for listing all the mon names and their corresponding IANA names.

I am attempting to find a user-friendly list of time zones for users to select their current time zone. It would have mon names that time zones that are referred to such as Pacific Time (US and Canada).

This list should map the text to an IANA standard name such as America/Los_Angeles.

It would also remove listings that the user thinks of as the "same" time zone. For example the listing for Pacific Time (US and Canada) would correspond to America/Los_Angeles and America/Tijuana, which are the "same" time.

I've tried looking in the IANA Time Zone Database, ECMA Script internationalization API, and libraries like Moment.js. They can parse the IANA name into the mon name, for example America/Los_Angeles ==> "Pacific Standard Time" but don't have a built-in function for listing all the mon names and their corresponding IANA names.

Share Improve this question edited Apr 14, 2020 at 20:36 nth-child asked Apr 13, 2020 at 10:58 nth-childnth-child 5608 silver badges17 bronze badges 6
  • How do you plan to use this list of names? The answer to that question will help determine the best way to retrieve and process the list you're looking for. For example, if you want a one-time dump, it might be simplest to import the current list of IANA names and mon names into a database and export the data in the format you want. OTOH, if you want a constantly up-to-date list, you'll have to find an API that provides the info. – kmoser Commented Apr 13, 2020 at 21:04
  • @kmoser A one-time dump is good. The names will be used as dropdown options. When a user registers on my website, I detect their timezone to set a default option which they can update if needed. The easy part is detecting the timezone, which is a simple API call. The tricky part is mapping all 300+ IANA names to 100 simplified dropdown options. It's tricky because one dropdown option corresponds to many IANA strings. – nth-child Commented Apr 13, 2020 at 22:39
  • 1 @kmoser I found this table of IANA names and mon names from Zoom API docs: marketplace.zoom.us/docs/api-reference/other-references/… It's missing a lot of IANA names though. What happens if the timezone detected does name match any of these IDs? Would you just write a rule to handle that? What would that rule be? – nth-child Commented Apr 13, 2020 at 22:46
  • @yogadog—that list is almost entirely bereft of timezone names. It only includes a handful of standard north American mon names and no daylight saving mon names. – RobG Commented Apr 14, 2020 at 6:06
  • @RobG True. But dropdown options ≠ timezone names. For example, when user is picking his "timezone" he doesn't select from “Pacific Daylight Time” and “Pacific Standard Time”. Instead, the dropdown uses one identifier such as Pacific (US & Canada), and prints his appointments in PDT and PST when appropriate. Dropdown options don't need to be named after timezone names. The goal is creating a sensible dropdown for user’s to pick from. Any ideas? – nth-child Commented Apr 14, 2020 at 8:08
 |  Show 1 more ment

3 Answers 3

Reset to default 4

The short answer is there is no simple map from IANA representative location names to mon names because the IANA name doesn't reflect historic changes in offset or daylight saving, nor are mon names sufficiently standardised either officially or de facto.

Long answer

IANA representative locations include historic changes in timezone offset, both for the local time and daylight saving as it has been applied over the years. The standard timezone name probably hasn't changed, however the offsets have and continue to. Also, the IANA representative location name stays the same during daylight saving, however the offset and mon name don't.

E.g. Samoa has an IANA name of "Pacific/Samoa". Its standard offset prior to 29 December 2011 was UTC−11:00 but after then its offset has been UTC+13:00, and its daylight saving time went from UTC-1000 to UTC+14:00. The mon names for its timezone are "Samoa Standard Time" and "Samoa Daylight Saving Time", however these names aren't standardised and in many places are ambiguous (e.g. CST might be central standard time in 2 or 3 different places, or China standard time).

So there is no simple map from IANA representative location name to mon timezone name for all IANA locations. You may be able to create one for a small subset, however using the built–in Intl object is likely simpler, e.g.

let opts = {
  hour: 'numeric',
  minute:'2-digit',
  timeZone: 'Pacific/Samoa',
  timeZoneName: 'long'
};
let time = new Date().toLocaleString('en', opts);
console.log('Currently in Samoa it\'s ' + time);

Note

On the latest version of MacOS, the above gives an offset for Samoa of UTC-1100 so still using old values, and it doesn't recognise daylight saving so the Intl object can't be relied upon.

You might use the Intl object as below, noting that for some locations it may not have a name for the timezone, so just shows the offset (e.g. try Europe/Astrakhan). There are nearly 600 IANA locations.

// Detect user representative location if available
let repLoc = (typeof Intl == 'object' && 
              typeof Intl.DateTimeFormat == 'function' &&
              typeof Intl.DateTimeFormat().resolvedOptions == 'function')?
              Intl.DateTimeFormat().resolvedOptions().timeZone : 'default';

function setRepLoc(evt) {
  showSampleDates(this.value);
}

function showSampleDates(repLoc) {
  let el0 = document.getElementById('sDate0');
  let el1 = document.getElementById('sOff0');
  let el2 = document.getElementById('sDate1');
  let el3 = document.getElementById('sOff1');

  let d0 = new Date(Date.UTC(2020,0,1,11));
  let d1 = new Date(Date.UTC(2020,5,1,11));
  let opts = {
    weekday: 'short',
    day: 'numeric',
    month: 'short',
    year: 'numeric',
    hour: 'numeric',
    minute: '2-digit',
    timeZone: repLoc,
    timeZoneName: 'long'
  };
  let offOpts = {
    hour: 'numeric',
    hour12: false,
    timeZone: repLoc,
    timeZoneName: 'short'
  }
  if (repLoc == 'default') {
    el0.textContent = '';
    el1.textContent = '';
    el2.textContent = '';
    el3.textContent = '';
  } else {
    el0.textContent = d0.toLocaleString('en-NZ', opts);
    el1.textContent = d0.toLocaleString('en-NZ', offOpts).split(' ')[1];
    el2.textContent = d1.toLocaleString('en-NZ', opts);
    el3.textContent = d1.toLocaleString('en-NZ', offOpts).split(' ')[1];
  }
}

window.onload = function(){
  let sel = document.getElementById('repLoc')
  if (repLoc) {
    sel.options[0].text = repLoc;
    sel.options[0].value = repLoc;
    sel.selectedIndex = 0;
    setRepLoc.call(sel);
  }
  sel.addEventListener(
    'change',
    setRepLoc,
    false);
};
td:nth-child(1){text-align:right;color:#999;}
td:nth-child(2){font-family:monospace}
<table>
  <tr>
    <td>IANA loc:
    <td><select id="repLoc">
          <option selected value="default">Select a location
          <option>Europe/Amsterdam
          <option>Europe/Andorra
          <option>Europe/Astrakhan
          <option>Europe/Athens
          <option>Europe/Belfast
          <option>Pacific/Samoa
          <option>Pacific/Kiritimati
          <option>Antarctica/DumontDUrville
          <option>Antarctica/Davis
          <option>America/Chicago
          <option>Australia/Brisbane
        </select>
  <tr>
    <td>Sample:
    <td id="sDate0">
  <tr>
    <td>Offset:
    <td id="sOff0">
  <tr>
    <td>Sample:
    <td id="sDate1">
  <tr>
    <td>Offset:
    <td id="sOff1">

</table>

You can use Intl.DateTimeFormat.prototype.formatToParts().

new Intl.DateTimeFormat(
    'default',
    { timeZone: 'America/Los_Angeles', timeZoneName: 'long' }
).formatToParts().find(({ type }) => type === 'timeZoneName').value
// 'Pacific Daylight Time'

Building on Kimamula's answer, I took the current list of IANA time zone names and ran it through my browser's Intl formatter to obtain long and short names for all of them. The result is a gist with a mapping of IANA names to human readable names. I've taken the 'generic' forms of these names, which omits mention of daylight saving time. Otherwise we would need to know whether DST is in effect to select the name. (e.g. Pacific Time instead of Pacific Standard Time or Pacific Daylight Time).

Not every timezone has an ideal name in this database, as with most things time related this will be an imperfect solution. But it will hopefully cover the time zones that are most popular with your users, and displaying an IANA name as a fallback is an option.

In case you want to generate these names yourself, you can run this in your browser. These names came from Firefox, I would guess that they are implementation dependent and might be a bit different in other browsers.


const iana_names = [
  "Africa/Abidjan",
  "Africa/Accra",
  "Africa/Addis_Ababa",
  // ...
  "W-SU",
  "WET",
  "Zulu"
]

const mapping = {}

iana_names.forEach( name => {

   const long = new Intl.DateTimeFormat('default', { timeZone: name, timeZoneName: 'longGeneric' }).formatToParts().find(({ type }) => type === 'timeZoneName').value
   const short = new Intl.DateTimeFormat('default', { timeZone: name, timeZoneName: 'shortGeneric' }).formatToParts().find(({ type }) => type === 'timeZoneName').value

   mapping[name] = {
     long, short
   }

})

本文标签: javascriptUserfriendly time zone names corresponding to IANA namesStack Overflow