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

时间:2013-06-27 16:46:03

标签: c# .net timezone nodatime

the timezone tag wiki所述,时区有两种不同的风格。

  • Microsoft提供的用于Windows和.Net TimeZoneInfo类的内容由Eastern Standard Time等值标识。

  • IANA在TZDB中提供的内容由America/New_York等值标识。

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

如何在.Net中实现这一目标?

3 个答案:

答案 0 :(得分:162)

Windows和IANA时区标识符之间转换数据的主要来源是windowsZones.xml文件,作为the 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"

还有更多示例on the project site

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

注意:这个答案多年来一直在发展,因此下面的评论可能适用于当前版本,也可能不适用。查看编辑历史记录以获取详细信感谢。

答案 1 :(得分:1)

我知道这是一个老问题,但是我有一个用例,尽管我会在这里分享,因为这是我在搜索时发现的最相关的帖子。我正在使用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")

答案 2 :(得分:1)

从 .NET 6 Preview 4 开始,it is finally possible 以跨平台方式处理时区,因此不再需要这些手动解决方法。

TimeZoneInfo.FindSystemTimeZoneById(string) 方法会自动接受任一平台上的 Windows 或 IANA 时区,并在需要时进行转换。

// Both of these will now work on any supported OS where ICU and time zone data are available.
TimeZoneInfo tzi1 = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
TimeZoneInfo tzi2 = TimeZoneInfo.FindSystemTimeZoneById("Australia/Sydney");

请注意,如链接中所指定,基于 .NET Core Alpine Linux 的 Docker 映像 do not have the necessary tzdata installed by default,因此它必须安装在您的 Dockerfile 中才能正常工作。