moment-timezone icon indicating copy to clipboard operation
moment-timezone copied to clipboard

Extend tz.names() to include more information

Open nlyn opened this issue 5 years ago • 4 comments

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:

Screenshot 2019-06-17 at 08 36 47

nlyn avatar Jun 17 '19 12:06 nlyn

if this hasn't been worked on, I can take a look into placing this enhancement

ODAVING avatar Nov 20 '19 22:11 ODAVING

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.

nareshbhatia avatar Apr 18 '20 21:04 nareshbhatia

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}`,
        };
    });

nareshbhatia avatar Apr 19 '20 00:04 nareshbhatia

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).

gilmoreorless avatar Jan 23 '21 06:01 gilmoreorless

Thank you @gilmoreorless for excellent explanation.

ichernev avatar Aug 27 '22 16:08 ichernev