如何在Windows和IANA时区之间转换?


149

时区标签wiki所述,时区有两种不同的样式。

  • Microsoft提供的与Windows和.Net TimeZoneInfo类一起使用的(在Windows上运行时)由诸如的值标识"Eastern Standard Time"

  • IANDB在TZDB中提供的,TimeZoneInfo在Linux或OSX上运行时由.NET 类使用的标识符由诸如的值标识"America/New_York"

许多基于Internet的API使用IANA时区,但由于多种原因,可能需要将其转换为Windows时区ID,反之亦然。

如何在.Net中完成?

Answers:


198

Windows和IANA时区标识符之间进行转换的数据的主要来源是windowsZones.xml作为Unicode CLDR项目的一部分分发的文件。最新的开发版本可以在这里找到。

但是,CLDR每年仅发布两次。这与Windows更新的定期节奏以及IANA时区数据库的不定期更新一起,使得直接使用CLDR数据变得很复杂。请记住,时区更改本身是由世界各国政府一时兴起的,并非所有更改都在引起足够注意的情况下进行以使其在各自的生效日期之前进入这些发布周期。

还有一些其他需要处理的极端情况,CLDR并未严格涵盖这些情况,并且不时弹出新的情况。因此,我将解决方案的复杂性封装到TimeZoneConverter微库中,该库可以从Nuget安装。

使用这个库很简单。以下是一些转换示例:

string tz = TZConvert.IanaToWindows("America/New_York");
// Result:  "Eastern Standard Time"

string tz = TZConvert.WindowsToIana("Eastern Standard Time");
// result:  "America/New_York"

string tz = TZConvert.WindowsToIana("Eastern Standard Time", "CA");
// result:  "America/Toronto"

项目站点上还有更多示例。

重要的是要认识到,虽然IANA时区可以映射到单个Windows时区,但事实并非如此。一个Windows时区可能映射到多个IANA时区。在上面的示例中可以看到这一点,其中Eastern Standard Time既映射到,也映射America/New_YorkAmerica/Toronto。TimeZoneConverter将提供带有CLDR标记的区域"001",称为“黄金区”,除非您专门提供了一个国家/地区代码,并且该国家/地区的另一个区域存在匹配项。

注意:多年来,此答案一直在发展,因此以下注释可能适用于当前修订版,也可能不适用于当前修订版。查看编辑历史记录以了解详细信息。谢谢。


1
转换时使用该方法(GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi给出了Asia/Calcutta它应该是Asia/Kolkata。似乎TzdbDateTimeZoneSource包含旧值。
Anto Subash 2014年

1
@MattJohnson在转换Asia/Kolkatausing IanaToWindows 方法时失败。但是它与Asia/Calcutta旧名称一起使用。您更新了方法,WindowsToIanaIanaToWindows也遇到了同样的问题。这不工作其他一些区域是America/Argentina/Buenos_AiresAmerica/Indiana/IndianapolisAsia/Kathmandu
Anto Subash 2014年

1
@AntoJSubash-再一次,伟大的观察!我已经编辑了IanaToWindows补偿方法。非常感谢!
Matt Johnson-Pint 2014年

2
@MattJohnson我第二@sirrocco的观察。像var canonical = tzdbSource.CanonicalIdMap[ ianaZoneId ]; links = Enumerable.Repeat( canonical, 1 ).Concat( links );我一样使用规范id也可以帮我。
约翰内斯·鲁道夫

2
@sirrocco-对不起,我没有尽快看到您的评论。更新了功能。谢谢!
马特·约翰逊

4

我知道这是一个老问题,但是我有一个用例,尽管我会在这里分享,因为这是我在搜索时找到的最相关的帖子。我正在使用docker linux容器开发.NET Core应用程序,但是要在Windows服务器上进行部署。所以我只需要我的docker linux容器来支持Windows时区名称。通过执行以下操作,我无需更改应用程序代码即可工作:

cp /usr/share/zoneinfo/America/Chicago "/usr/share/zoneinfo/Central Standard Time"
cp /usr/share/zoneinfo/America/New_York "/usr/share/zoneinfo/Eastern Standard Time"
cp /usr/share/zoneinfo/America/Denver "/usr/share/zoneinfo/Mountain Standard Time"
cp /usr/share/zoneinfo/America/Los_Angeles "/usr/share/zoneinfo/Pacific Standard Time"

然后,在我的.NET代码中,以下内容无需任何修改即可工作: TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time")


1
开箱即用的想法真是太棒了!只要您涵盖几个特定的​​时区,这似乎应该没问题。请记住,在美国,有四个以上的国家。为了弥补在现今的50个州中,你还需要添加链接,America/Phoenix"US Mountain Standard Time"Pacific/Honolulu"Hawaiian Standard Time"America/Anchorage"Alaskan Standard Time",并America/Adak"Aleutian Standard Time"。这不涉及美国领土或历史差异,但可以帮助您入门。
马特·约翰逊

2
如果一个人的意图是覆盖整个世界或处理任何有效的时区标识符,我将不推荐这种方法。该列表太长且太易变。
马特·约翰逊
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.