2013-03-08 107 views
42

TimeZoneInfo不提供給定時區的縮寫或短名稱。唯一的好辦法是製作一個字典,將縮寫映射到Timezone.id,StandardNameDaylightName屬性。但是,我搜索縮寫列表的所有資源都有不同的時區名稱,即與Windows中不同。時區縮寫

如何在.NET中顯示用戶不是全名,ID或任何其他名稱?我不想要UtcOffset,但時區的縮寫 - PST爲太平洋,UTC爲通用,EST - 爲東部標準等。是否有任何C#兼容的列表或數據庫與所有可能的時區及其縮寫兼容的那些TimeZoneInfo.GetSystemTimeZones()給予您?

+4

正如你所說 - 縮寫的時區名稱的問題是它們有多重含義。他們最好在國際申請中避免。例如,[EST](http://en.wikipedia.org/wiki/EST)至少有5個不同的時區含義。 – Oded 2013-03-08 19:53:50

+0

那麼你總是可以提供縮寫和偏移量。但大多數時候只顯示偏移量不夠。 – Agzam 2013-03-08 20:30:38

回答

12

這是一個棘手的需求,你可以做的最好的是獲得你選擇的列表並創建一個擴展/幫助方法來獲得給定TimeZoneInfo的縮寫。

一旦開始的地方在http://www.timeanddate.com/library/abbreviations/timezones/其中有一個列表的版本,涵蓋了我所知道的區域。

問題在於如果在給定時區內存在多個存在的情況下選擇適當的縮寫。例如UTC可以表示爲UTCWET(西歐時間)WEZ(Westeuropäische時代週報)WT(西撒哈拉標準時間)

您可能想要與您的利益相關者就您將遵循給定選擇的命名約定達成一致。

+1

但不是已經有「熟」的解決方案 - 字典或映射系統時區ID縮寫的文件?我試圖從你指向的那個網站上提取數據,但它最多給了我14個可能的值。必須有更多的... – Agzam 2013-03-08 21:45:34

+0

我只是舉一個例子,你可以在網上獲得大量的名單,例如:http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations。但問題是要知道你想使用什麼樣的縮寫。 – 2013-03-08 21:51:05

50

修訂ANSWER

我原來的響應之下,仍然有效。但是現在有一種更簡單的方法,使用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既有數據庫又有映射。您可以從.Net DateTimeDateTimeOffsetTimeZoneInfo,到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

僅供參考,您需要使用當前庫版本添加額外的TimeZoneNames。'var abbrZoneName = TimeZoneNames.TimeZoneNames.GetAbbreviationsForTimeZone(zoneName,lang);' – 2015-09-29 20:56:12

+0

是的,我應該給出不同的命名空間和類名稱。現在太晚了,但是哦。 :) – 2016-01-11 17:27:20

+0

@KurtWagner - 剛剛添加了一堆2.0.0的東西,並決定做一個突破性的改變來解決命名問題。該類被重命名爲'TZNames',所以它不會與名稱空間衝突。 – 2016-04-06 06:33:25

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

在我的系統這產生了: 「2013年4月11日下午5時03分23秒CDT(UTC-05:00美國/芝加哥)」

(感謝馬特·約翰遜的回答爲縮寫住在TimeZoneInterval線索)

這將是更容易,如果NodaTime.ZonedDateTime有GetZoneInterval方法,但也許我錯過someth ING。

10

您的問題並未指出您的應用程序必須在哪些時區運行,但在我的特殊情況下,我只需要關注美國時區和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()函數的代碼非常簡單。值得一提的是,某些時區可能設置爲墨西哥或加拿大,而這些時區的名稱將在括號內以國名命名,例如「Pacific Standard Time(Mexico)」。爲了解決這個問題,任何括號數據都直接返回。爲上述返回的縮寫將是「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; 
} 
+0

適用於我在Windows中獲得的135個時區嗎? – Kiquenet 2018-03-01 12:28:58

+0

@Kiquenetu我不知道。正如答案中所述,它適用於美國時區和UTC。 – STLDeveloper 2018-03-01 12:32:13

0

我有一個類似的問題,但不想使用第三方庫(因爲大多數這些答案都提示)。如果您只想支持.Net的時區名稱,並決定使用查找表,請查看my answer over here,它依賴於PHP來幫助生成縮寫列表。您可以根據需要調整代碼片段和表格。

+0

請不要將鏈接發佈到[重複答案](// meta.stackexchange.com/a/211726/206345)。相反,考慮其他可以幫助未來用戶找到他們需要的答案的行動,如鏈接文章中所述。或者,爲特定問題制定一個獨立的答案。 – Mogsdad 2016-03-22 19:48:15

+0

@Mogsdad我不明白這個問題。該meta post可以解決多個問題的複製/粘貼問題。我確實對這個問題的答案進行了調整,但由於這個相關問題提出了稍微不同的要求,所以我在這裏引用它以防未來的讀者。我在回答中特別指出,它與其他人不同,因爲它不使用第三方庫。 – QuickDanger 2016-03-22 20:59:29

0

這對任何使用Xamarin for iOS或Android的人都很有幫助,因爲根據文檔「顯示名稱是基於Windows操作系統安裝的文化進行本地化」。在中央時區使用此功能時,對於日期時間「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; 
}