如何在Windows和IANA时区之间进行翻译?
如时区标记wiki中所述 ,有两种不同的时区样式。
-
由Microsoft提供的用于Windows和.Net
TimeZoneInfo
类的值由诸如Eastern Standard Time
类的值标识。 -
IANA在TZDB中提供的数据通过诸如
America/New_York
的值来确定。
许多基于互联网的API使用IANA时区,但出于多种原因,可能需要将其转换为Windows时区ID,反之亦然。
这怎么能在.Net中完成呢?
Windows和IANA时区标识符之间转换数据的主要来源是Unicode CLDR的一部分。
在大多数情况下,IANA时区可映射到单个Windows时区。 但相反是不正确的。 单个Windows时区可能会映射到多个IANA时区。
更新解决方案
现在,使用我的TimeZoneConverter微库,现在更容易和可维护。
例子:
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"
项目网站上的更多示例
原始解决方案(从2013年起 – 仍然有效)
除了作为高级日期时间API之外, Noda时间库还包含CLDR映射的嵌入副本。
以下功能可用于转换:
// This will return the Windows zone that matches the IANA zone, if one exists. public string IanaToWindows(string ianaZoneId) { var utcZones = new[] { "Etc/UTC", "Etc/UCT", "Etc/GMT" }; if (utcZones.Contains(ianaZoneId, StringComparer.Ordinal)) return "UTC"; var tzdbSource = NodaTime.TimeZones.TzdbDateTimeZoneSource.Default; // resolve any link, since the CLDR doesn't necessarily use canonical IDs var links = tzdbSource.CanonicalIdMap .Where(x => x.Value.Equals(ianaZoneId, StringComparison.Ordinal)) .Select(x => x.Key); // resolve canonical zones, and include original zone as well var possibleZones = tzdbSource.CanonicalIdMap.ContainsKey(ianaZoneId) ? links.Concat(new[] {tzdbSource.CanonicalIdMap[ianaZoneId], ianaZoneId}) : links; // map the windows zone var mappings = tzdbSource.WindowsMapping.MapZones; var item = mappings.FirstOrDefault(x => x.TzdbIds.Any(possibleZones.Contains)); if (item == null) return null; return item.WindowsId; } // This will return the "primary" IANA zone that matches the given windows zone. // If the primary zone is a link, it then resolves it to the canonical ID. public string WindowsToIana(string windowsZoneId) { if (windowsZoneId.Equals("UTC", StringComparison.Ordinal)) return "Etc/UTC"; var tzdbSource = NodaTime.TimeZones.TzdbDateTimeZoneSource.Default; var tzi = TimeZoneInfo.FindSystemTimeZoneById(windowsZoneId); if (tzi == null) return null; var tzid = tzdbSource.MapTimeZoneId(tzi); if (tzid == null) return null; return tzdbSource.CanonicalIdMap[tzid]; }
请注意,UTC的映射必须单独处理。 这是因为CLDR将UTC错误地映射为"Etc/GMT"
,并且"Etc/GMT"
未在tzdb中设置为"Etc/UTC"
的链接。 更多关于这里。
- 什么是解除操作员?
- 为什么字典偏好Hashtable?
- C#中的错误:“expression式树可能不包含基本访问” – 为什么不?
- 什么时候应该打开和closures连接到SQL Server
- 为什么需要XmlNamespaceManager?
- 无法在C#应用程序中为我的线程使用多个处理器组
- Gmail错误:SMTP服务器需要安全连接或客户端未通过身份validation。 服务器响应是:5.5.1需要身份validation
- 不能将types'System.Collections.Generic.IEnumerable <AnonymousType#1>'隐式转换为'System.Collections.Generic.List <string>
- WCF:暴露只读的DataMember属性没有设置?