Azure Maps 和 SQL AT TIME ZONE 与夏威夷的时区不兼容

Azure Maps and SQL AT TIME ZONE incompatible time zone for Hawaii

我只是 运行 在使用 Azure Maps 为时区提供的数据尝试使用 AT TIME ZONE 在 SQL 服务器(Azure SQL)中获取本地时间时出现问题].

当我向 Azure Maps 提供夏威夷位置的 lat/long 数据时,return 显示 "Hawaii-Aleutian Standard Time":

"Names":{  
        "ISO6391LanguageCode":"en",
        "Generic":"Hawaii-Aleutian Time",
        "Standard":"Hawaii-Aleutian Standard Time",
        "Daylight":"Hawaii-Aleutian Daylight Time"
     },

在我系统的另一部分,我需要能够确定 SQL 服务器中该位置的本地时间,因此我使用 AT TIME ZONE 并注入标准时区。这适用于我正在处理的美国时区,例如 "Eastern Standard Time" 或 "Central Standard Time"。当它到达夏威夷位置时...它出错并说它不是一个有效的时区。

查看我在网上找到的 SQL 服务器的时区列表,看来夏威夷在 SQL 的时区是 "Hawaiian Standard Time"。

还有其他人 运行 遇到这种情况吗?

我想我需要修正一些异常代码,以用 "Hawaiian Standard Time" 替换这个 Azure 提供的时区。有更好的解决方案吗?

这里有一个示例供参考 URL(减号):https://atlas.microsoft.com/timezone/byCoordinates/json?subscription-key={key}&api-version=1.0&options=all&query=21.4500,-158.0054

这是完整的 JSON returned:

{
  "Version": "2018g",
  "ReferenceUtcTimestamp": "2018-12-08T17:10:31.8007137Z",
  "TimeZones": [
    {
      "Id": "Pacific/Honolulu",
      "Aliases": [
        "Pacific/Johnston",
        "US/Hawaii"
      ],
      "Countries": [
        {
          "Name": "United States",
          "Code": "US"
        },
        {
          "Name": "US minor outlying islands",
          "Code": "UM"
        }
      ],
      "Names": {
        "ISO6391LanguageCode": "en",
        "Generic": "Hawaii-Aleutian Time",
        "Standard": "Hawaii-Aleutian Standard Time",
        "Daylight": "Hawaii-Aleutian Daylight Time"
      },
      "ReferenceTime": {
        "Tag": "HST",
        "StandardOffset": "-10:00:00",
        "DaylightSavings": "00:00:00",
        "WallTime": "2018-12-08T07:10:31.8007137-10:00",
        "PosixTzValidYear": 2018,
        "PosixTz": "HST+10"
      },
      "RepresentativePoint": {
        "Latitude": 21.306944444444444,
        "Longitude": -157.85833333333332
      },
      "TimeTransitions": [
        {
          "Tag": "HST",
          "StandardOffset": "-10:00:00",
          "DaylightSavings": "00:00:00",
          "UtcStart": "1947-06-08T12:30:00Z",
          "UtcEnd": "9999-12-31T23:59:59.9999999Z"
        }
      ]
    }
  ]
}

好的,"Pacific/Honolulu" 是 IANA 代码。根据一些 SQL 文档,它支持所有 Windows 时区,而其他文档说它只支持机器注册表中的时区,这可能因机器而异。物理检查我的机器我可以看到 SQL 支持 137 个时区(Select * 来自 sys.time_zone_info)。然而,根据 Windows 文档,它有 250 个默认时区(加上一些扩展时区)。在某些地方肯定存在断开连接,但它看起来更像是 Windows/SQL 断开连接。

也就是说,"Hawaiian Standard Time" 和 "Hawaii-Aleutian Standard Time" 似乎是相同的:https://www.timeanddate.com/time/zones/hast

然而,当谈到夏令时时,它变得更加复杂:https://www.timeanddate.com/time/zones/hadt

我会将此线程传递给 Azure Maps 工程和数据团队进行更深入的调查。

Names 部分返回的字符串不是标识符。它们是源自 Unicode CLDR 的本地化字符串,旨在向最终用户显示。虽然其中一些在以英文呈现时可能与标识符对齐,但不能保证这一点。

它们也不是随意选择的。 "Hawaii-Aleutian Time" 确实是这个时区的法定名称,由 15 USC 260 (and described on Wikipedia here) 定义。

另一方面,SQL 服务器的时区功能严格依赖于 Windows 时区标识符,可以在 Windows 注册表中找到,或者通过各种 APIs(例如 .NET 的 TimeZoneInfo.Id)和命令行实用程序(例如 TZUTIL /L 返回的每对结果的第一行)。

不幸的是,Azure Maps API 目前似乎只有 returns IANA ID,而不是相应的 Windows ID。我已经要求 Azure Maps API 团队考虑在未来的版本中添加它。

同时,您可以将IANA ID转换为对应的Windows ID,然后再在SQL服务器中使用。假设您在 .NET 应用程序中,执行此操作的最简单方法是使用我的 TimeZoneConverter 库:

string tz = TZConvert.IanaToWindows("Pacific/Honolulu");  //=>  "Hawaiian Standard Time"

如果您不在 .NET 中,您可以使用 Windows 中内置的文件,路径为:

C:\Windows\Globalization\Time Zone\timezoneMapping.xml

该文件包含如下所示的条目:

<MapTZ TZID="Pacific/Honolulu" WinID="Hawaiian Standard Time" Region="001" Default="true" StdPath="Hawaii_Aleutian/standard" DltPath="Hawaii_Aleutian/daylight" />

您只需使用 TZIDWinID 属性在该方向进行映射。

或者,您可以使用 CLDR 的 /common/supplemental/windowsZones.xml 文件,因为这是权威来源。开发主干版本位于 here。其数据看起来相似,但属性命名不同:

<mapZone other="Hawaiian Standard Time" territory="001" type="Pacific/Honolulu"/>