3

I want to get the country code for any country based on the current timezone.

To achieve this I am using Momentjs and countries-and-timezones packages in my react js project.

Everything is working fine except sometimes for (UTC +01:00) West Central Africa timezone I am getting these values Africa/Lagos and Africa/Luanda.

In my case, I wanted the country code for Angola whose capital is Luanda but since I am using countries-and-timezones it doesn't have Africa/Luanda as the timezone of Angola which is throwing an undefined error.

And when I looked into Momentjs' packed data.json file I found this: "Africa/Lagos|Africa/Luanda". And this is not the only time zone which is being updated, there are many.

So what I want to know is:
How can I get the original value Africa/Lagos from the Moment.tz.guess() function. Because I don't want to edit the data.json that I am using from countries-and-timezones to correct the error. Also, I found many such JSON files which contain the same old timezones.

Or is there any better library to get the country code from timezones because I can't use any services like timezonedb or ip-api to get the country code from IP addresses. Any help is much appreciated.

mplungjan
  • 169,008
  • 28
  • 173
  • 236
vibhor
  • 66
  • 3

1 Answers1

2

... sometimes for (UTC+01:00) West Central Africa timezone I am getting these values Africa/Lagos and Africa/Luanda.

That is correct. There are multiple valid IANA time zone mappings for the Windows time zone you mentioned. The Unicode CLDR is the authority for these mappings, which you can view in the windowsZones.xml file, and presently looks like this:

<!--  (UTC+01:00) West Central Africa  -->
<mapZone other="W. Central Africa Standard Time" territory="001" type="Africa/Lagos"/>
<mapZone other="W. Central Africa Standard Time" territory="AO" type="Africa/Luanda"/>
<mapZone other="W. Central Africa Standard Time" territory="BJ" type="Africa/Porto-Novo"/>
<mapZone other="W. Central Africa Standard Time" territory="CD" type="Africa/Kinshasa"/>
<mapZone other="W. Central Africa Standard Time" territory="CF" type="Africa/Bangui"/>
<mapZone other="W. Central Africa Standard Time" territory="CG" type="Africa/Brazzaville"/>
<mapZone other="W. Central Africa Standard Time" territory="CM" type="Africa/Douala"/>
<mapZone other="W. Central Africa Standard Time" territory="DZ" type="Africa/Algiers"/>
<mapZone other="W. Central Africa Standard Time" territory="GA" type="Africa/Libreville"/>
<mapZone other="W. Central Africa Standard Time" territory="GQ" type="Africa/Malabo"/>
<mapZone other="W. Central Africa Standard Time" territory="NE" type="Africa/Niamey"/>
<mapZone other="W. Central Africa Standard Time" territory="NG" type="Africa/Lagos"/>
<mapZone other="W. Central Africa Standard Time" territory="TD" type="Africa/Ndjamena"/>
<mapZone other="W. Central Africa Standard Time" territory="TN" type="Africa/Tunis"/>
<mapZone other="W. Central Africa Standard Time" territory="ZZ" type="Etc/GMT-1"/>

For the most part, all of the IANA zones listed are equivalent, and all align with the given Windows zone. Africa/Lagos is given by CLDR as the "golden zone" (by territory="001"). Generally, an implementation should use the country-code specific mapping when a country code is available, and use the golden zone otherwise.

... since I am using countries-and-timezones it doesn't have Africa/Luanda as the timezone of Angola ...

From looking at the GitHub sources of that particular package, it is not clear where their data originates. Also, it has not been updated in 3 years. Without regular updates and a clear source of origin, such packages are not generally useful (IMHO).

... when I looked into Momentjs' packed data.json file I found this: "Africa/Lagos|Africa/Luanda". And this is not the only time zone which is being updated, there are many.

Indeed, Moment-timezone will link equivalent zones. One implementation detail to recognize is that moment won't necessarily place the "golden zone" first. It just goes in alphabetical order, and when it sees two zones with the same data, it combines them. This is relatively unimportant, as the time zones themselves do indeed have the same data (offsets, transitions, and abbreviations match).

How can I get the original value Africa/Lagos from the Moment.tz.guess() function.

Well, there's no "original" value here, so you can't. The original value would be the Windows time zone ("W. Central Africa Standard Time"). Moment first tries to use the JavaScript Intl API to get an IANA time zone ID directly from your browser - so depending on implementation, the browser could return any equivalent time zone ID. Thus some implementations may give Africa/Lagos, and some may give Africa/Luanda, or any of the others in the CLDR mapping for this zone.

For implementations where the Intl API is not present, moment.tz.guess will test the offsets of your local time zone against the data it has (whatever you have loaded), and pick one that matches. If there's a tie, there's some additional data included about populations to pick the more common one. You can read about these details in the moment-timezone docs and in the implementation of the moment.tz.guess function in the source code.

Keep in mind that just because you are getting different results from moment.tz.guess in different environments does not mean that these results are invalid. You should still be able to use any result returned to you.

Or is there any better library to get the country code from timezones ...

I don't know of a well-maintained library for JavaScript that conveniently does this for you yet. I'm tempted to create one (as I've already done for .NET), but in the mean time, you could read the JSON version of the CLDR mapping file and parse through it yourself.

... because I can't use any services like timezonedb or ip-api to get the country code from IP addresses ...

Besides IP address, you might consider if you have a location with latitude/longitude available to you? If so, look in to the methods listed in this question for how to use that to get a time zone id.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575