首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >TimeZone转换显示EDT而不是EST

TimeZone转换显示EDT而不是EST
EN

Stack Overflow用户
提问于 2014-04-06 05:00:29
回答 1查看 3.8K关注 0票数 1

我使用这段代码将“东部时区”转换为"EST“。现在它正在播放"EDT“。你不会经常在一些地方看到这样的缩写,你想坚持"EST“。我如何在NodaTime中做到这一点?

代码语言:javascript
运行
复制
 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;
        }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-04-08 00:39:16

更新

下面的答案描述了如何解析和使用CLDR数据。这很好,但是我把所有这些都包含在一个库中,使它变得更容易了。请参阅这个StackOverflow的答案读我的博文,并查看TimeZoneNames库。使用这个库比自己解析CLDR数据容易得多。

代码语言:javascript
运行
复制
// 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数据使用以下步骤来实现您的目标:

  1. 找到与Windows相对应的IANA时区ID,就像您在上面的代码中所做的那样,或者直接使用CLDR窗口时区映射
  2. CLDR MetaZones文件中查找IANA时区。
  3. 在CLDR转换的MetaZone中查找数据文件,或像这个这样的图表。使用"generic-long""generic-short"模式,以及您选择的语言,例如英语的"en"

所以,在您的例子中,首先从TimeZoneInfo.Id of "Eastern Standard Time"开始

  1. IANA区= "America/New_York"
  2. CLDR = "America_Eastern"
  3. 泛型-long en = "Eastern Time" 泛型-短en = "ET"

请注意,并非每个Windows时区都可映射到IANA区域,也不是每个元区域都有一个短名称,而且一些从未遵循夏令时的区域将只具有标准名称而不是泛型名称。

下面是一些C#代码,展示了如何遍历CLDR的XML数据以获取TimeZoneInfo对象的通用长名称。它假设您可以在指定的路径上访问CLDR数据。下载最新的core.zip并解压缩,然后将basePath指向该文件夹。

代码语言:javascript
运行
复制
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;
}

调用它将为您提供一个字典,然后您可以使用它来查找。示例:

代码语言:javascript
运行
复制
// 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];
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22890184

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档