C# 时区缩写

C# 时区缩写,c#,.net,timezone,C#,.net,Timezone,时区信息不提供给定时区的缩写或简称。唯一的好方法是有一个字典,它可以将缩写映射到时区.id、标准名称或DaylightName属性。但是,我搜索的所有缩写列表的来源都有不同的时区名称,即与Windows中的不同 如何在.NET中向用户显示非全名、id或任何其他名称?我不想要UtcOffset,但是时区的缩写——太平洋的PST,环球的UTC,东方标准的EST等等。是否有任何C兼容的列表或数据库,包含所有可能的时区及其缩写,与TimeZoneInfo.GetSystemTimeZones()提供给您

时区信息
不提供给定时区的缩写或简称。唯一的好方法是有一个字典,它可以将缩写映射到
时区.id
标准名称
DaylightName
属性。但是,我搜索的所有缩写列表的来源都有不同的时区名称,即与Windows中的不同


如何在.NET中向用户显示非全名、id或任何其他名称?我不想要UtcOffset,但是时区的缩写——太平洋的PST,环球的UTC,东方标准的EST等等。是否有任何C兼容的列表或数据库,包含所有可能的时区及其缩写,与
TimeZoneInfo.GetSystemTimeZones()提供给您的那些兼容?

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

一旦开始的地方是有一个版本的列表,其中包括我知道的区域

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


您可能希望与您的利益相关者就您将要遵循的命名约定达成一致。

更新答案

我最初的答复如下,仍然有效。然而,现在有一种更简单的方法,使用。安装后,您可以执行以下操作:

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中维护

具有数据库和映射。您可以使用
TimeZoneInfo
从.Net
DateTime
DateTimeOffset
转到NodaTime
Instant
DateTimeZone
。从那里,你可以得到缩写名

// 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);

下面是使用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);
NodeTime.ZonedDateTime hereAndNow=NodeTime.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,
区域偏移
在我的系统中,这会产生:“2013年11月4日下午5:03:23 CDT(UTC-05:00美国/芝加哥)”

(感谢马特·约翰逊的回答,因为他提供了这个缩写存在于时区区间的线索)


如果NodaTime.zoneDateTime有一个GetZoneInterval方法,那就容易多了,但也许我遗漏了一些东西

您的问题并没有说明您的应用程序必须在哪个时区内运行,但在我的特殊情况下,我只需要关注美国时区和UTC

美国时区的缩写始终是时区名称中每个单词的第一个字符。例如,“山区标准时间”的缩写为“MST”,而“东部夏时制”的缩写为“EDT”

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

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;
}

我也有类似的问题,但不想使用第三方库(正如大多数答案所示)。如果您只想支持.Net的时区名称,并决定使用查找表,请看一看,它依靠PHP帮助生成缩写列表。您可以根据自己的需要修改其中的代码片段和表格。

这对任何使用Xamarin for iOS或Android的人都很有帮助,因为根据文档“显示名称是基于Windows操作系统安装的区域性本地化的。”在中央时区中使用此选项时,对于DateTime“2016-09-01 12:00:00 GMT”,此函数返回“CDT”,这正是我遇到此问题时所需要的

public static string GetTimeZoneAbbreviation(DateTime time)
{
    string timeZoneAbbr;
    if(time.IsDaylightSavingTime() == true)
    {
        timeZoneAbbr = TimeZoneInfo.Local.DaylightName;
    }
    else
    {
        timeZoneAbbr = TimeZoneInfo.Local.StandardName;
    }

    return timeZoneAbbr;
}

我将所有日期存储在UTC中,通常必须在本地时间显示,因此我创建了一个扩展方法
toabrevision()

或者,如果您只想从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

正如您所说-缩写时区名称的问题是它们有多种含义。在国际应用程序中最好避免使用。例如,至少有5种不同的时区含义。您始终可以提供缩写和偏移量。但大多数时间显示j除掉
string tz = TimeZone.CurrentTimeZone.ToAbbreviation();
string formattedDate = String.Format("{0:yyyy/MM/dd hh:mm:ss} {1}", myDate, tz);
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()