Windows 上如果設定了時區(無論手動或自動),透過 TimeZoneInfo 取出的時區識別碼,都是根據所設定的地區的時區,並且回應成 Windows 使用的 TimeZone 格式識別碼。

例如設定為 (UTC +08:00) 台北取出來的識別碼的值會為:"Taipei Standard Time" 的字串資料。
但是…
如果需要跨平台到其他的系統當中使用此資料,例如: macOS、Linux 則需要轉換基於 Time Zone Database 所使用的 "Iana 時間格式" 來運用。
所以如果在 .NET 6 以後的 .NET 程式,已經可以透過 TimeZoneInfo 的 TryConvertWindowsIdToIanaId 方法來進行轉換。
也就是說如果在 Windows 上要取得當前電腦所設定的時區拋去給其他系統使用時,在 .NET 6 以後的 .NET 程式可以這樣處理:
var timeZoneInfoLocal = TimeZoneInfo.Local;
Console.WriteLine($"Local Id: {timeZoneInfoLocal.Id}, UtcOffSet: {timeZoneInfoLocal.BaseUtcOffset}");
var windowsId = timeZoneInfoLocal.Id;
Console.WriteLine($"WindowsId: {windowsId}");
TimeZoneInfo.TryConvertWindowsIdToIanaId(windowsId, out var ianaId);
Console.WriteLine($"IanaId: {ianaId}");
其輸出結果大致上為:
Local Id: Taipei Standard Time, UtcOffSet: 08:00:00
WindowsId: Taipei Standard Time
IanaId: Asia/Taipei
透過 LINQPad 來做上述程式的測試與結果展示:

其結果相當合理。
且此方法是從 .NET 6 開始就有的 .NET API,應該沒什麼太大問題。

果然…不出意外馬上就要出意外了。
沒多久就發現在某些特定的 Windows 設備上且有確定是 UTC+08:00 的 Taipei 時區,透過使用此轉換方式居然失效?!轉換出來的 "ianaId" 值居然是 Null,且 TryConvertWindowsIdToIanaId 方法還真的回傳了 false。
趕緊仔細研讀了文件上的 "備註":

並且注意到了 "NLS 模式"。
連結過去看了 ".NET 全球化和 ICU" 的文件說明,在 Windows 上的 ICU 說明為:

注意何謂舊版 Windows 與 各 .NET 版本的搭配,請審視上圖的表列。
其中說明文件的 ICU 相依 API 的部分,更點出了該 TryConvertWindowsIdToIanaId 方法 並特別說明:

結果就是中槍,這些設備的執行環境 (Windows 版本 與 .NET 版本) 完全符合成為 "NLS 模式" 的執行,並未能正確使用 ICU 模式。
所以…如果真的遇到這樣的狀況時,其解決方式呢?
至少有兩個方案可以使用。
方案 A:按照微軟說明文件使用 "應用程式本機 ICU"。
在專案中安裝 "Microsoft.ICU.ICU4C.Runtime" 的 Nuget 套件並且採用 "應用程式本機 ICU" 中所描述的三種方式,挑選任何其中一種方式進行設定:

方案 B:透過 NodaTime 的 Nuget 套件來進行。

利用 NodaTime 撰寫其程式碼大致如下:
var windowsId = TimeZoneInfo.Local.Id;
var ianaTimeZoneId = TzdbDateTimeZoneSource.Default
.WindowsMapping.PrimaryMapping.TryGetValue(windowsId, out var ianaId)
? ianaId
: string.Empty;
if (!string.IsNullOrEmpty(ianaTimeZoneId))
{
Console.WriteLine($"WindowsId: {windowsId}");
Console.WriteLine($"IanaId: {ianaId}");
}
else
{
Console.WriteLine("No IANA mapping found for the given Windows time zone.");
}
其輸出結果大致上為:
WindowsId: Taipei Standard Time
IanaId: Asia/Taipei
透過 LINQPad 來做上述程式的測試與結果展示:

當然若使用 NodaTime 也能帶來處理其他 DateTime 上的問題與轉換的方便性就是。
以上結案~~~
所以各位看倌,要使用 .NET API 時文件內容一定要看清楚阿…
I'm a Microsoft MVP - Developer Technologies (From 2015 ~).

I focus on the following topics: Xamarin Technology, Azure, Mobile DevOps, and Microsoft EM+S.
If you want to know more about them, welcome to my website:
https://jamestsai.tw
本部落格文章之圖片相關後製處理皆透過 Techsmith 公司 所贊助其授權使用之 "Snagit" 與 "Snagit Editor" 軟體製作。