moment-timezone
moment-timezone copied to clipboard
Extend tz.names() to include more information
I'd suggest even extending this a little bit more so that what gets returned is an array of objects, with each object containing the offset, the TZ database name, a readable name and as a bonus, maybe even an array with the countries that are in time timezone. This way, we could use the method to populate fields like this:

if this hasn't been worked on, I can take a look into placing this enhancement
This is exactly what I am looking for! The issue with showing just a sorted list of IANA timezones is that user may not know what to pick for their desired location. For example, a user in Salt Lake City, UT may have no clue that they should pick America/Denver. However if we sort by timezone offsets, they can get a sense by looking at the GMT offset:
(GMT-06:00) America/Denver
Also knowing their own offset, they can quickly scroll the the right place.
I know that there is an issue with offsets because they are relative to a specific time, but showing the offset at current time gives us a good solution for 80% of the use cases.
Of course, having the ability to show a more readable name would be a bonus.
P.S. Is there a way to get an array of all zone objects? https://github.com/moment/moment-timezone/issues/43 mentioned that there is a global variable called momentTZData
, but I couldn't find it. Could it be because I am using it in a React app which is packaged using Webpack? Would be nice to expose it using a real API.
After reading the docs again, I was able to display timezones sorted by offsets. The trick was to get a zone object and then call zone.utcOffset(Date.now())
to get its current offset.
const tzOptions: Array<OptionType> = moment.tz
.names()
.map((name) => {
const now = Date.now();
const zone = moment.tz.zone(name);
return { name, offset: zone !== null ? zone.utcOffset(now) : 0 };
})
.sort((a, b) =>
a.offset === b.offset
? a.name.localeCompare(b.name)
: b.offset - a.offset
)
.map((zone) => {
const gmtOffset = `GMT${moment.tz(zone.name).format('Z')}`;
const abbr = moment.tz(zone.name).format('z');
return {
value: zone.name,
label: `(${gmtOffset}) ${zone.name} - ${abbr}`,
};
});
The IANA time zone database doesn't contain long-form names for time zones as shown in the opening screenshot, so getting that data into Moment Timezone wouldn't be possible just using the existing data source.
The Unicode Common Locale Data Repository (CLDR) is the best source for this kind of information. It contains mappings between IANA ids (e.g. America/Denver
) and locale-dependent long names, so they're not hard-coded to English. However, including CLDR data within Moment Timezone has generally been considered out-of-scope, partly because it's not a straightforward task (see https://github.com/moment/moment-timezone/issues/227#issuecomment-194983870).
Thank you @gilmoreorless for excellent explanation.