Moment-timezone: I don't see a way to get an easy list of the available timezones

Created on 5 Nov 2013  路  23Comments  路  Source: moment/moment-timezone

My use case is populating a select element with options for the available timezones so the user can set their timezone. I was hoping for something along the lines of

moment.tz.getTimezones()
which would return something like

[
    {
        name: "Eastern Standard Time"
      , locale: "America/New_York"
      , abbreviation: "EST"
      , offset: "-5"
    }
  , {
        name: "Central Standard Time"
      , abbreviation: "CST"
      , locale: "America/Chicago"
      , offset: "-6"
    }
]

Most helpful comment

Using moment.tz.names() returns a list of over 500 elements, is it possible to condense that down so that there is just one for each zone? If this were to be used to populate a drop down to allow a user to select their timezone, then it would be completely impractical

All 23 comments

Hi. A few things:

  • The zone _name_ is "America/New_York". That's not the locale.
  • Determining an offset and an abbreviation requires a specific point in time. It's invalid to say that "America/New_York" == -5, since in daylight time it is -4.
  • Abbreviations are somewhat ambiguous. The best we could do is return the TZDB's representation of the abbreviation, which is somewhat arbitrary and still ambiguous. For example, both America/Chicago and Asia/Shanghai use the abbreviation CST, along with several of other locations.
  • Determining a zone _description_ such as "Eastern Standard Time" would require both a point in time, and also localization data from the CLDR which is too large for moment-timezone. For example, we might call Europe/Moscow "Moscow Standard Time" in English, but the CLDR shows us that the Russians call it "袦芯褋泻胁邪, 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟".

So when you take all of this into consideration, the best we could do would be to spit out an array of all of the time zone names that we know about, such as ["America/Chicago","Europe/London","Africa/Johannesburg"] for example.

Thank you for the response and the clarifications, my example was just a rough sketch of what was desired, pardon my misconceptions. I appreciate the work done on this library, this request should really just be considered an "enhancement" request, since it is not regarding anything wrong with moment-timezone.

I do believe that even something as simple as "an array of all of the time zone names that we know about, such as ["America/Chicago","Europe/London","Africa/Johannesburg"]" would be useful.

Regarding the offset being invalid, what about an "offset" and "offsetDST", returning, say, -5 and -4 respectively?

Regarding the descriptions such as "Eastern Standard Time", plugging "袦芯褋泻胁邪, 褋褌邪薪写邪褉褌薪芯械 胁褉械屑褟" into Google translate outputs "Moscow Standard Time", so it appears to simply be a 1:1 translation. Perhaps the library can simply return the English description and that can be handled by however an application chooses to do localization?

Lastly, regarding any of the data that would need a "point in time" for referencing, maybe it could be an optional parameter like moment.tz.getTimezones( referenceTime ), whereas moment.tz.getTimezones() would simply base it off the current date/time.

My use case for this was simply wanting to populate a select field on a web app with a list of selectable timezones for the user. Right now I have to make my own data structure, which is not a huge deal but if I add a new timezone to the zones data passed in to moment.tz.add then I have to remember to update my reference structure as well, which is not ideal.

Rather than using your own data structure, you could just iterate through the data in the momentTZData object. Not exactly a public API, but you should be able to reuse it.

Have you considered instead using a map-based timezone picker? They tend to work much better with end-users than drop-down lists. Take a look at this one or this one.

As previously suggested, it sounds like you need CLDR. A colleague of mine has written a handy module for getting that data out: https://github.com/papandreou/node-cldr

(AFAIK, we generate the required client-side source-code from CLDR using this module; that way we only send the data we actually need...)

@msiebuhr Thanks for the link! I haven't had the time to investigate CLDR for JS libraries yet, but I will take a further look at that one. Can you elaborate on that second part? Are you using this in the browser?

We have a build-system (https://github.com/One-com/assetgraph; like these Grunt-build thingies, except it actually understands HTML, CSS, JS, ... and applies all sorts of optimizations on it) where we generate all (or: as much as we can) data like this up front. AFAIK, we don't touch CLDR once inside the browser.

This issue raises an interesting challenge: Building any app that is designed to be globally available but locally consumed will have to account for UTC to local conversion. moment-timezone seems great at the conversion, but seems to not really address configuration to a specific timezone.

@mj1856 I agree that Visual Maps can be a good way of selecting, but I'm trying to focus on building an experience that always degrades to mobile well. Neither of those two do, while a good old dropdown list with a word-wheel does.

You mentioned momentTZData but I can't find any mention of that. All I need is an Array of the timezone names as @hughlomas mentioned.

momentTZData is created on the global scope when you call moment.tz.add(...) when establishing the time zone data. So you can examine it and pull out the keys for the time zones. Using a library like underscore.js can make this trivial:

var zones = _.keys(momentTZData.zones)

I couldn't figure out how to retrieve the global momentTZData, so I created it as a global directly above the call to moment.tz.add and then referenced it. Thus, timezones load correctly and you can reference the zones object. Quick fix, but it works for now.

var momentTZData = {
        "America/Adak": [
...
moment.tz.add({
    "zones": momentTZData,
    "rules": {
...
var zones = _.keys(momentTZData)

I could not find any usage of moment.momentTZData on my local copy of moment-timezone, even after calling moment.tz.add(...). I do however see it on the http://momentjs.com/timezone/ website. I ended up doing what @merrihew suggested.

I also did a quick search and don't see any mention of momentTZData in the codebase.

Here's what I do.

var timeZonesList = moment.tz.zones().map(function (zone) {
    return {
        name: zone.displayName,
        abbr: moment.tz(zone.displayName).zoneAbbr()
    };
});

This has been added in 0.1.0 as moment.tz.names().

http://momentjs.com/timezone/docs/#/data-loading/getting-zone-names/

Using moment.tz.names() returns a list of over 500 elements, is it possible to condense that down so that there is just one for each zone? If this were to be used to populate a drop down to allow a user to select their timezone, then it would be completely impractical

@elewin see #227. But also, listing out the IANA identifiers isn't so great anyway. One needs CLDR data to do it right. There's certainly room for a javascript-only version of something like my demo here.

Oh, and please don't make a habit of commenting on years-old-closed issues. ;)

@markuso - ERROR TypeError: moment.tz.zones is not a function, which version of momentjs you are using?

@psagar5 Use the new moment.tz.names() instead for latest version. See the comment right after my old one here. I have switched to that. So you don't need my solution anymore. The underscore _ is the reference to lodash, but I changed my old comment right now to use plain JS .map() method.

@markuso - i am getting list either 592 or 365 (if i filter out) entries for moment.tz.names(). Is there any way to use standard timezones, smaller list?
I guess there are 37 standard timezones.

@markuso - please let me know if there is any way to filter the list to get less than 50 timezones?

@psagar5 I am not aware of any smaller list or a specific way to filter the list to some sort of standard short list. To cover worldwide time zones, you need the full list. In our application, we just show the full list to our users grouped by the first section of each name. Like "America" heading for all the "America/*" zones, etc.

Sorry, maybe someone else could have a better answer about a standard short list you speak of.

What we ended up doing was mapping the IANA time zones to Windows time zones, then we let the user select a windows time zone to narrow things down, then drill down further and list all the IANA time zones that fall under it so they can select the IANA time zone that applies specifically to them. It is much easier to quickly narrow down the time zones you present to the user that way.

@elewin - can you share code snippet of your implementation?

@psagar5 Sure,
So first we create a big array of objects, each object is a Windows time zone. Within each object, it then has its own array of IANA time zones that map to it

 [
// . . .
   {
   "value": "Pacific Standard Time",
   "abbr": "PDT",
   "offset": -7,
   "isdst": true,
   "text": "(UTC-08:00) Pacific Time (US & Canada)",
   "utc": [
     "America/Dawson",
     "America/Los_Angeles",
     "America/Tijuana",
     "America/Vancouver",
     "America/Whitehorse",
     "PST8PDT"
   ]
 }, {
   "value": "US Mountain Standard Time",
   "abbr": "UMST",
   "offset": -7,
   "isdst": false,
   "text": "(UTC-07:00) Arizona",
   "utc": [
     "America/Creston",
     "America/Dawson_Creek",
     "America/Hermosillo",
     "America/Phoenix",
     "Etc/GMT+7"
   ]
 }, {
   "value": "Mountain Standard Time (Mexico)",
   "abbr": "MDT",
   "offset": -6,
   "isdst": true,
   "text": "(UTC-07:00) Chihuahua, La Paz, Mazatlan",
   "utc": [
     "America/Chihuahua",
     "America/Mazatlan"
   ]
 }, {
   "value": "Mountain Standard Time",
   "abbr": "MDT",
   "offset": -6,
   "isdst": true,
   "text": "(UTC-07:00) Mountain Time (US & Canada)",
   "utc": [
     "America/Boise",
     "America/Cambridge_Bay",
     "America/Denver",
     "America/Edmonton",
     "America/Inuvik",
     "America/Ojinaga",
     "America/Yellowknife",
     "MST7MDT"
   ]
 },
// . . .
]       

Then, on the UI we have a drop-down that shows the text property of each element of the above array of Windows time zones, and when the user selects one of those, a second part of the UI then displays the array of IANA time zones (the utc array in the selected object) and then the user can select the specific time zone that belongs to them.

I don't remember where we got that map of time zones from though; I can't recall if its something that we compiled our self or if it's from some other open source project; if its from another open source project then apologies to whoever wrote it, at the moment I can't find the original link where its from to give proper credit :(

Was this page helpful?
0 / 5 - 0 ratings