Moment时区检测时区,给相同时区提供不同的值

时间:2018-09-29 14:39:51

标签: javascript datetime timezone momentjs

我想根据当前时区获取任何国家的国家代码。

要实现此目的,我在我的react js项目中使用了Momentjscountries-and-timezones包。

一切正常,除了有时在(UTC +01:00) West Central Africa时区,我得到了这些值Africa/LagosAfrica/Luanda

在我的情况下,我想要首都为罗安达的安哥拉的国家代码,但是由于我使用的是countries-and-timezones,因此没有Africa/Luanda作为安哥拉的时区,这会引发未定义的错误。

当我查看Momentjs打包的data.json文件时,发现:"Africa/Lagos|Africa/Luanda"。这不是唯一要更新的时区,有很多。

所以我想知道的是:
如何从Africa/Lagos函数中获取原始值Moment.tz.guess()。因为我不想从countries-and-timezones编辑我正在使用的data.json来更正错误。另外,我发现许多此类JSON文件都包含相同的旧时区。

或者有没有更好的库可以从时区获取国家/地区代码,因为我不能使用timezonedbip-api之类的任何服务从IP地址获取国家/地区代码。非常感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

  

...有时在(UTC+01:00) West Central Africa时区,我会得到这些值Africa/LagosAfrica/Luanda

是正确的。您提到的Windows时区有多个有效的IANA时区映射。 Unicode CLDR是这些映射的权限,您可以在windowsZones.xml文件中查看,目前看起来像这样:

<!--  (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"/>

在大多数情况下,列出的所有IANA区域都是等效的,并且都与给定的Windows区域对齐。 CLDR将Africa/Lagos称为“黄金地带”(territory="001")。通常,在国家/地区代码可用时,实现应使用国家/地区代码特定的映射,否则请使用黄金区域。

  

...由于我使用的是countries-and-timezones,因此没有非洲/罗安达作为安哥拉的时区...

通过查看该特定程序包的GitHub来源,尚不清楚其数据源自何处。另外,它已经3年没有更新了。如果没有定期更新和明确的来源,此类软件包通常就不可用(IMHO)。

  

...当我查看Momentjs打包的data.json文件时,发现:“ Africa / Lagos | Africa / Luanda”。这不是唯一要更新的时区,有很多。

实际上,Moment-timezone将链接等效的区域。要认识到的一个实现细节是,此刻不一定会把“黄金地带”放在第一位。它只是按字母顺序排列,当看到两个具有相同数据的区域时,它将它们组合在一起。这是相对不重要的,因为时区本身确实具有相同的数据(偏移量,转换和缩写匹配)。

  

如何从Moment.tz.guess()函数获得原始值Africa / Lagos。

好吧,这里没有“原始”值,所以您不能。原始值为Windows时区(“ W.中非标准时间”)。 Moment首先尝试使用JavaScript Intl API直接从浏览器获取IANA时区ID-因此,根据实现的不同,浏览器可能会返回 any 等效时区ID。因此,在此区域的CLDR映射中,某些实现可能会给出Africa/Lagos,有些可能会给出Africa/Luanda,或者其他任何实现。

对于没有使用Intl API的实现,moment.tz.guess会根据其拥有的数据(无论装入了什么)测试本地时区的偏移量,然后选择一个匹配的数据。如果有平局,则其中包含一些有关人口的其他数据,以选择更常见的人口。您可以在一下时区文档中以及源代码中moment.tz.guess函数的实现中了解这些详细信息。

请记住,仅仅因为您在不同环境中从moment.tz.guess获得了不同的结果,并不意味着这些结果是无效的。您仍然应该能够使用返回给您的任何结果。

  

或者有没有更好的库可以从时区获取国家/地区代码...

我不知道一个维护良好的JavaScript库可以方便地为您完成此操作。我很想创建一个(就像我对.NET所做的那样),但是与此同时,您可以阅读JSON version of the CLDR mapping file并自己解析。

  

...因为我无法使用timezonedb或ip-api之类的任何服务来从IP地址获取国家/地区代码...

除了IP地址,您可能还会考虑是否有一个可以提供经度/纬度的位置?如果是这样,请查看in this question中列出的方法,以了解如何使用该方法获取时区ID。