时区缩写

时间:2013-03-08 19:47:35

标签: c# .net timezone

TimeZoneInfo不为给定时区提供缩写或短名称。唯一的好方法是使用字典将缩写映射到Timezone.idStandardNameDaylightName属性。但是,我搜索缩写列表的所有源都有不同的时区名称,即与Windows中的不同。

如何在.NET中向用户显示全名,ID或任何其他名称?我不想要UtcOffset而是时区缩写 - 太平洋的PST,UTC - 适用于Universal,EST - 适用于东部标准等。是否有任何C#兼容列表或数据库,其中包含所有可能的时区及其缩写,与{{{ 1}}给你?

7 个答案:

答案 0 :(得分:62)

更新的答案

我的原始回复如下,仍然有效。但是现在有一种更简单的方法,使用the TimeZoneNames library。安装from Nuget后,您可以执行以下操作:

string tzid = theTimeZoneInfo.Id;                // example: "Eastern Standard time"
string lang = CultureInfo.CurrentCulture.Name;   // example: "en-US"
var abbreviations = TZNames.GetAbbreviationsForTimeZone(tzid, lang);

生成的对象将具有类似于以下属性:

abbreviations.Generic == "ET"
abbreviations.Standard == "EST"
abbreviations.Daylight == "EDT"

您还可以使用此相同的库来获取时区的完全本地化名称。该库使用CLDR数据的嵌入式自包含副本。

原始回答

正如其他人所提到的,时区缩写是模棱两可的。但如果你真的想要一个展示,你需要一个IANA / Olson时区数据库。

您可以从Windows时区转到IANA / Olson时区,也可以转到其他方向。但请注意,任何给定的Windows区域都可能有多个IANA / Olson区域。这些映射保留在CLDR here中。

NodaTime同时包含数据库和映射。您可以从带有DateTime的.Net DateTimeOffsetTimeZoneInfo转到NodaTime InstantDateTimeZone。从那里,您可以获得缩写名称。

// starting with a .Net TimeZoneInfo
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");

// You need to resolve to a specific instant in time - a noda Instant
// For illustrative purposes, I'll start from a regular .Net UTC DateTime
var dateTime = DateTime.UtcNow;
var instant = Instant.FromDateTimeUtc(dateTime);

// note that if we really wanted to just get the current instant,
// it's better and easier to use the following:
// var instant = SystemClock.Instance.Now;


// Now let's map the Windows time zone to an IANA/Olson time zone,
// using the CLDR mappings embedded in NodaTime.  This will use
// the *primary* mapping from the CLDR - that is, the ones marked
// as "territory 001".

// we need the NodaTime tzdb source.  In NodaTime 1.1.0+:
var tzdbSource = TzdbDateTimeZoneSource.Default;

// in previous NodaTime releases:
// var tzdbSource = new TzdbDateTimeZoneSource("NodaTime.TimeZones.Tzdb");

// map to the appropriate IANA/Olson tzid
var tzid = tzdbSource.MapTimeZoneId(timeZoneInfo);

// get a DateTimeZone from that id
var dateTimeZone = DateTimeZoneProviders.Tzdb[tzid];


// Finally, let's figure out what the abbreviation is
// for the instant and zone we have.

// now get a ZoneInterval for the zone and the instant
var zoneInterval = dateTimeZone.GetZoneInterval(instant);

// finally, you can get the correct time zone abbreviation
var abbreviation = zoneInterval.Name;

// abbreviation will be either PST or PDT depending
// on what instant was provided
Debug.WriteLine(abbreviation);

答案 1 :(得分:13)

这是一个棘手的要求,您可以做的最好的事情是获取您选择的列表并创建扩展/帮助方法以获取给定TimeZoneInfo的缩写。

一旦开始就在http://www.timeanddate.com/library/abbreviations/timezones/,其中有一个列表版本,涵盖了我所知道的区域。

问题在于选择适当的缩写,其中给定时区存在多个缩写。例如, UTC 可以表示为 UTC WET(西欧时间) WEZ(WesteuropäischeZeit) WT(西撒哈拉标准时间)

您可能希望与您的利益相关方就您将遵循给定选择的命名惯例达成一致。

答案 2 :(得分:12)

您的问题并未说明您的申请必须在哪个时区内运作,但在我的特定情况下,我只需要关注美国时区和UTC。

美国时区的缩写始终是时区名称中每个单词的第一个字符。例如,“Mountain Standard Time”的缩写是“MST”,“Eastern Daylight Time”的缩写是“EDT”。

如果您有类似的要求,您可以直接从本地时区的名称直接导出本地时区的时区缩写,如下所示(注意:这里我根据当前日期和时间确定正确的名称):

string timeZoneName = TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now)
                          ? TimeZone.CurrentTimeZone.DaylightName 
                          : TimeZone.CurrentTimeZone.StandardName;

string timeZoneAbbrev = GetTzAbbreviation(timeZoneName);

GetTzInitials()函数的代码非常简单。值得一提的是,某些时区可能设置为墨西哥或加拿大,这些时区的名称将在括号中加上国家名称,例如“太平洋标准时间(墨西哥)”。为了解决这个问题,任何带括号的数据都会直接传回。上面返回的缩写将是“PST(墨西哥)”,这对我有用。

string GetTzAbbreviation(string timeZoneName) {
    string output = string.Empty;

    string[] timeZoneWords = timeZoneName.Split(' ');
    foreach (string timeZoneWord in timeZoneWords) {
        if (timeZoneWord[0] != '(') {
            output += timeZoneWord[0];
        } else {
            output += timeZoneWord;
        }
    }
    return output;
}

答案 3 :(得分:2)

这是使用NodaTime的另一个代码段:

NodaTime.ZonedDateTime hereAndNow = NodaTime.SystemClock.Instance.Now.InZone(
    NodaTime.DateTimeZoneProviders.Tzdb.GetSystemDefault());

System.TimeSpan zoneOffset = hereAndNow.ToDateTimeOffset().Offset;

string sTimeDisplay = string.Format("{0:G} {1} (UTC{2}{3:hh\\:mm} {4})", 
    hereAndNow.ToDateTimeOffset(), 
    hereAndNow.Zone.GetZoneInterval(hereAndNow.ToInstant()).Name, 
    zoneOffset < TimeSpan.Zero ? "-" : "+", 
    zoneOffset, 
    hereAndNow.Zone.Id);

在我的系统上,这会产生:“4/11/2013 5:03:23 PM CDT(UTC-05:00 America / Chicago)”

(感谢Matt Johnson对线索的回答,即缩写存在于TimeZoneInterval中)

如果NodaTime.ZonedDateTime有一个GetZoneInterval方法会更容易,但也许我错过了一些东西。

答案 4 :(得分:1)

我有类似的问题,但不想使用第三方库(正如大多数这些答案所示)。如果您只想支持.Net的时区名称,并决定使用查找表,请查看my answer over here,它依靠PHP来帮助生成缩写列表。您可以根据需要调整代码段和表格。

答案 5 :(得分:1)

这对于使用Xamarin for iOS或Android的任何人都很有用,因为根据文档&#34;显示名称是根据随Windows操作系统安装的文化进行本地化的。&#34;在中央时区使用此功能时,对于DateTime&#34; 2016-09-01 12:00:00 GMT&#34;,此功能将返回&#34; CDT&#34;这正是我在遇到这个问题时所需要的。

\w+

答案 6 :(得分:0)

我将所有日期存储在UTC中,并且经常不得不在当地时间显示它们,因此我创建了扩展方法ToAbbreviation()

    public static string ToAbbreviation(this TimeZone theTimeZone)
    {

        string timeZoneString = theTimeZone.StandardName;
        string result = string.Concat(System.Text.RegularExpressions.Regex
           .Matches(timeZoneString, "[A-Z]")
           .OfType<System.Text.RegularExpressions.Match>()
           .Select(match => match.Value));

        return result;
    }

用法示例:

string tz = TimeZone.CurrentTimeZone.ToAbbreviation();
string formattedDate = String.Format("{0:yyyy/MM/dd hh:mm:ss} {1}", myDate, tz);

或者,如果您只想从DateTime对象获取格式化的日期字符串:

public static string ToLocalTimeWithTimeZoneAbbreviation(this DateTime dt)
{
    DateTime localtime = dt.ToLocalTime();
    string tz = TimeZone.CurrentTimeZone.ToAbbreviation();

    string formattedDate = String.Format("{0:yyyy/MM/dd hh:mm:ss} {1}", localtime, tz);
    return formattedDate;
}

并使用如下:

string formattedDate = myDateTimeObject.ToLocalTimeWithTimeZoneAbbreviation()

输出:2019-06-24 02:26:31 EST