我使用这段代码将“东部时区”转换为"EST“。现在它正在播放"EDT“。你不会经常在一些地方看到这样的缩写,你想坚持"EST“。我如何在NodaTime中做到这一点?
public static string GetTimeZoneAbbr(string timeZone)
{
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
if (timeZoneInfo != null)
{
var dateTime = DateTime.UtcNow;
var instant = Instant.FromDateTimeUtc(dateTime);
var tzdbSource = TzdbDateTimeZoneSource.Default;
var tzid = tzdbSource.MapTimeZoneId(timeZoneInfo);
var dateTimeZone = DateTimeZoneProviders.Tzdb[tzid];
var zoneInterval = dateTimeZone.GetZoneInterval(instant);
return zoneInterval.Name;
}
return string.Empty;
}
发布于 2014-04-08 00:39:16
更新
下面的答案描述了如何解析和使用CLDR数据。这很好,但是我把所有这些都包含在一个库中,使它变得更容易了。请参阅这个StackOverflow的答案,读我的博文,并查看TimeZoneNames库。使用这个库比自己解析CLDR数据容易得多。
// You can pass either type of time zone identifier:
var tz = "America/New_York"; // IANA
var tz = "Eastern Standard Time"; // Windows
// You can get names or abbreviations for any language or locale
var names = TZNames.GetNamesForTimeZone(tz, "en-US");
var abbreviations = TZNames.GetAbbreviationsForTimeZone(tz, "en-US");
names.Generic == "Eastern Time"
names.Standard == "Eastern Standard Time"
names.Daylight == "Eastern Daylight Time"
abbreviations.Generic == "ET"
abbreviations.Standard == "EST"
abbreviations.Daylight == "EDT"
原始答案
我在问题中写了一点评论,为什么显示缩写形式是完全有效的,但请允许我也回答这个问题。
以另一种方式重申您的问题,您希望从Microsoft时区id开始,并以一个人类可读的字符串结束,该字符串表示整个时区,而不仅仅是有效的时区段。
您可以只给他们TimeZoneInfo.DisplayName
,但这并不总是合适的。对于美国,您可能会得到一个"(UTC-05:00) Eastern Time (US & Canada)
的显示名称,您可以去掉前面的偏移量和括号,只需返回"Eastern Time (US & Canada)"
。但这并不适用于所有时区,因为许多时区只显示列出城市的名称,比如"(UTC-04:00) Georgetown, La Paz, Manaus, San Juan"
。
更好的方法是使用来自Unicode CLDR项目的数据。Noda Time有一部分数据,但并不是解决这个特定问题所需的全部数据。所以我不能给出一个使用Noda Time的代码示例。但是,可以对原始CLDR数据使用以下步骤来实现您的目标:
"generic-long"
或"generic-short"
模式,以及您选择的语言,例如英语的"en"
。所以,在您的例子中,首先从TimeZoneInfo.Id
of "Eastern Standard Time"
开始
"America/New_York"
"America_Eastern"
"Eastern Time"
泛型-短en = "ET"
请注意,并非每个Windows时区都可映射到IANA区域,也不是每个元区域都有一个短名称,而且一些从未遵循夏令时的区域将只具有标准名称而不是泛型名称。
下面是一些C#代码,展示了如何遍历CLDR的XML数据以获取TimeZoneInfo
对象的通用长名称。它假设您可以在指定的路径上访问CLDR数据。下载最新的core.zip并解压缩,然后将basePath
指向该文件夹。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
static Dictionary<TimeZoneInfo, string> GetCldrGenericLongNames(string basePath, string language)
{
// Set some file paths
string winZonePath = basePath + @"\common\supplemental\windowsZones.xml";
string metaZonePath = basePath + @"\common\supplemental\metaZones.xml";
string langDataPath = basePath + @"\common\main\" + language + ".xml";
// Make sure the files exist
if (!File.Exists(winZonePath) || !File.Exists(metaZonePath) || !File.Exists(langDataPath))
{
throw new FileNotFoundException("Could not find CLDR files with language '" + language + "'.");
}
// Load the data files
var xmlWinZones = XDocument.Load(winZonePath);
var xmlMetaZones = XDocument.Load(metaZonePath);
var xmlLangData = XDocument.Load(langDataPath);
// Prepare the results dictionary
var results = new Dictionary<TimeZoneInfo, string>();
// Loop for each Windows time zone
foreach (var timeZoneInfo in TimeZoneInfo.GetSystemTimeZones())
{
// Get the IANA zone from the Windows zone
string pathToMapZone = "/supplementalData/windowsZones/mapTimezones/mapZone" +
"[@territory='001' and @other='" + timeZoneInfo.Id + "']";
var mapZoneNode = xmlWinZones.XPathSelectElement(pathToMapZone);
if (mapZoneNode == null) continue;
string primaryIanaZone = mapZoneNode.Attribute("type").Value;
// Get the MetaZone from the IANA zone
string pathToMetaZone = "/supplementalData/metaZones/metazoneInfo/timezone[@type='" + primaryIanaZone + "']/usesMetazone";
var metaZoneNode = xmlMetaZones.XPathSelectElements(pathToMetaZone).LastOrDefault();
if (metaZoneNode == null) continue;
string metaZone = metaZoneNode.Attribute("mzone").Value;
// Get the generic name for the MetaZone
string pathToNames = "/ldml/dates/timeZoneNames/metazone[@type='" + metaZone + "']/long";
var nameNodes = xmlLangData.XPathSelectElement(pathToNames);
var genericNameNode = nameNodes.Element("generic");
var standardNameNode = nameNodes.Element("standard");
string name = genericNameNode != null
? genericNameNode.Value
: standardNameNode != null
? standardNameNode.Value
: null;
// If we have valid results, add to the dictionary
if (name != null)
{
results.Add(timeZoneInfo, name);
}
}
return results;
}
调用它将为您提供一个字典,然后您可以使用它来查找。示例:
// load the data once an cache it in a static variable
const string basePath = @"C:\path\to\extracted\cldr\core";
private static readonly Dictionary<TimeZoneInfo, string> timeZoneNames =
GetCldrGenericLongNames(basePath, "en");
// then later access it like this
string tzname = timeZoneNames[yourTimeZoneInfoObject];
https://stackoverflow.com/questions/22890184
复制相似问题