vvo / tzdb

🕰 Simplified, grouped and always up to date list of time zones, with major cities
MIT License
772 stars 53 forks source link

Incorrect abbreviation and alternativeName? #287

Open marcoancona opened 1 year ago

marcoancona commented 1 year ago

How is the mapping IANA -> abbreviation built? Let's take Europe/London as an example:

{
    "name": "Europe/London",
    "alternativeName": "Greenwich Mean Time",
    "group": [
        "Europe/London",
        "GB",
        "GB-Eire",
        "Europe/Guernsey",
        "Europe/Isle_of_Man",
        "Europe/Jersey",
        "Europe/Belfast"
    ],
    "continentCode": "EU",
    "continentName": "Europe",
    "countryName": "United Kingdom",
    "countryCode": "GB",
    "mainCities": [
        "London",
        "Birmingham",
        "Liverpool",
        "Glasgow"
    ],
    "rawOffsetInMinutes": 0,
    "abbreviation": "GMT",
    "rawFormat": "+00:00 Greenwich Mean Time - London, Birmingham, Liverpool, Glasgow",
    "currentTimeOffsetInMinutes": 60,
    "currentTimeFormat": "+01:00 Greenwich Mean Time - London, Birmingham, Liverpool, Glasgow"
}

Europe/London is equivalent to Greenwich Mean Time (GMT) only in Winter. In summer, shouldn't it be British Summer Time (BST)? GMT has a fixed offset, so what is the meaning of +01:00 Greenwich Mean Time?

cordosvictor commented 1 year ago

@marcoancona did you find an answer by now? Or an alternative solution? In summer I want to get "British Summer Time (BST)" for "Europe/London" time zone and only in winter "Greenwich Mean Time". This is not the case with the latest version of this library.

harelcoman commented 4 months ago

Any news about this issue, It makes us add tailor-made solution and we would love for this to be supported in the library, We shows longer and shortened version of the tz so showing just GMT is just wrong in our case

volstas commented 2 weeks ago

Kinda insane how hard it is to get correct list of timezones. Been looking for hours and every library has some kind of issues.

volstas commented 1 week ago

So, i made a quick fix for myself that works for the most part.

    const alternativeNameCorrections: any = {
        'Antarctica/Palmer': 'Chile Time',
        'America/Punta_Arenas': 'Chile Time',
        'Africa/Casablanca': 'Western European Time',
        'Africa/El_Aaiun': 'Western European Time',
        'Europe/Istanbul': 'Turkey Time',
        'Asia/Urumqi': 'China Time',
        'Pacific/Bougainville': 'Bougainville Time'
    };

    let timeZonesWithUtc = getTimeZones({ includeUtc: true }).map((x) => {
        let date = DateTime.now().setLocale('en-US').setZone(x.name);
        // If the environment doesn't support this time zone, we just keep the default pre-generated options
        if (date.invalidReason != null) {
            return x;
        }

        const fullAltName = date.toFormat(`ZZZZZ`);
        const prevAltName = x.alternativeName;
        let nextAltName = fullAltName
            .replace(/Standard Time/g, 'Time')
            .replace(/Daylight Time/g, 'Time')
            .replace(/Summer Time/g, 'Time');

        if (prevAltName != nextAltName) {
            // there are some cases where Node.js tz data won't be giving actual alternative names
            // for time zones and instead will send GMT +03:00, so we fix that
            if (/^GMT[+-]\d{2}:\d{2}$/.test(nextAltName)) {
                nextAltName = alternativeNameCorrections[x.name] || nextAltName;
            }

            if (prevAltName != nextAltName) {
                x.alternativeName = nextAltName;
                console.log(prevAltName + '>' + nextAltName + '(' + x.name + ')');
            }
        }

        const prevAbr = x.abbreviation;
        let nextAbr = abbreviations[fullAltName] || prevAbr;
        if (prevAbr != nextAbr) {
            x.abbreviation = nextAbr;
            console.log(prevAbr + '>' + nextAbr + '(' + x.name + ')');
        }

        return x;
    });

Basically the issue is that the generate logic uses a hardcoded January date for everything(https://github.com/vvo/tzdb/blob/main/generate.js#L228). So it's always in winter time. Here I recalculate the values based on current date.

The not so nice thing about this is that it needs to rerun and recalculate over 300 items every time unless you cache it somewhere.

If anyone wants to actually make a PR or a forked project based on this, it would be great.(if no one picks it up, I might do it myself after a month or two) I checked, and if you generate the names in January and July you get all options. It includes all the variants of all timezones.

So generate the names on both dates, make the alternativeName and abbreviation into arrays to include all possible options. And add currentAltnernativeName and currentAbbreviation.