【问题标题】:Moment timezone detect timezone giving different values for same timezone时刻时区检测时区为同一时区提供不同的值
【发布时间】:2018-09-29 14:39:50
【问题描述】:

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

为了实现这一点,我在我的 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"。这不是唯一正在更新的时区,还有很多。

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

或者有没有更好的库来从时区获取国家代码,因为我无法使用timezonedbip-api 等任何服务从 IP 地址获取国家代码。非常感谢任何帮助。

【问题讨论】:

    标签: javascript datetime timezone momentjs


    【解决方案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 区域对齐。 Africa/Lagos 被 CLDR 指定为“黄金地带”(territory="001")。通常,当国家代码可用时,实现应使用国家代码特定映射,否则使用黄金地带。

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

    通过查看该特定包的 GitHub 源,尚不清楚其数据的来源。而且,它已经3年没有更新了。如果没有定期更新和明确的来源,此类软件包通常没有用处(恕我直言)。

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

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

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

    嗯,这里没有“原始”价值,所以你不能。原始值将是 Windows 时区(“W. Central Africa Standard Time”)。 Moment 首先尝试使用 JavaScript Intl API 直接从您的浏览器获取 IANA 时区 ID - 因此根据实现,浏览器可以返回 any 等效时区 ID。因此,一些实现可能会给出Africa/Lagos,一些可能会给出Africa/Luanda,或者该区域的 CLDR 映射中的任何其他实现。

    对于不存在 Intl API 的实现,moment.tz.guess 将根据其拥有的数据(无论您加载什么)测试您本地时区的偏移量,并选择一个匹配的。如果出现平局,则包含一些关于人口的额外数据,以选择更常见的数据。您可以在 moment-timezone 文档和源代码中 moment.tz.guess 函数的实现中了解这些详细信息。

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

    或者有没有更好的库来从时区获取国家代码...

    我还不知道有一个维护良好的 JavaScript 库可以方便地为您做到这一点。我很想创建一个(就像我已经为 .NET 所做的那样),但与此同时,您可以阅读 JSON version of the CLDR mapping file 并自己解析它。

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

    除了 IP 地址之外,您还可以考虑是否有可用的纬度/经度位置?如果是这样,请查看列出的方法 in this question 了解如何使用它来获取时区 ID。

    【讨论】:

      猜你喜欢
      • 2019-02-12
      • 2013-02-12
      • 2018-09-08
      • 2020-08-10
      • 2016-04-30
      • 2016-08-16
      • 2020-07-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多