如果我有一些 UTC 时间,我如何在 C# 中获得相应的波兰当地时间?还是在法国?还是在厄瓜多尔?
在 Windows 上:
var poland = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTimeOffset.UtcNow, "Central European Standard Time");
var france = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTimeOffset.UtcNow, "Romance Standard Time");
var ecuador1 = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTimeOffset.UtcNow, "SA Pacific Standard Time"); // (Mainland)
var ecuador2 = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTimeOffset.UtcNow, "Central America Standard Time"); // (Galapagos Is.)
在 Linux、OSX 和其他 .NET Core 平台上:
var poland = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTimeOffset.UtcNow, "Europe/Warsaw");
var france = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTimeOffset.UtcNow, "Europe/Paris");
var ecuador1 = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTimeOffset.UtcNow, "America/Guayaquil"); // (Mainland)
var ecuador2 = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTimeOffset.UtcNow, "Pacific/Galapagos"); // (Galapagos Is.)
(注意Ecuador has two time zones,大陆一个,加拉帕戈斯群岛一个。)
CLDR windowsZones.xml file 是确定要使用哪个 Windows ID 的一个很好的参考,它是在 Windows 和 IANA 时区标识符之间转换的真实来源。
(我知道这对于像俄罗斯这样多次使用的大国来说没有意义)
确实,俄罗斯有许多个不同的时区标识符。人们必须知道他们对俄罗斯的哪个部分感兴趣。
在大多数现有示例中,人们使用TimeZoneInfo 对象:
var zone = TimeZoneInfo.FindSystemTimeZoneById("SE Asia Standard Time");
问题是这还不够。很多国家都有东西
比如“夏令时”或“daylight saving
time”,他们
根据一年中的哪一天使用与 UTC 不同的时间偏移量
甚至是准确的时间(在时间变化的当天)。
例如,我不想知道我是否需要Central Daylight
Time 或Central Standard Time 选项,而是希望能够选择
America/Chicago 让它为我处理。
不,这不是问题。您可能对该要求感到困惑,因为“标准”一词在标识符的名称中。尽管如此,TimeZoneInfo 对象仍代表整个时区,包括标准时间和夏令时。
为了澄清,TimeZoneInfo.FindSystemTimeZoneById 方法需要一个标识符。结果对象的Id 属性将包含该标识符。
-
"America/Chicago" 是 IANA 时区标识符。
-
"Central Standard Time" 既是 Windows 时区标识符,又是同一时区的英文本地化“标准名称”(在 Windows 上)。
-
"Central Daylight Time" 是该区域的英文本地化“日光名称”(在 Windows 上)。它不是有效的时区标识符。
是否有任何 C# 内置函数可以处理这个问题,或者我需要
处理夏令时开始和结束的所有计算
根据自己选择的国家的法律?
所有内置计算都处理这个问题。只传递有效的标识符,框架将确定与 UTC 的正确偏移量,无论是标准时间还是夏令时/夏令时有效。
这是一个演示这些概念的working example:
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time"); // Use "America/Chicago" on non-Windows systems
Console.WriteLine("Id: " + tzi.Id);
Console.WriteLine("DisplayName: " + tzi.DisplayName);
Console.WriteLine("StandardName: " + tzi.StandardName);
Console.WriteLine("DaylightName: " + tzi.DaylightName);
Console.WriteLine();
DateTime winterDate = new DateTime(2020, 1, 1);
DateTime summerDate = new DateTime(2020, 7, 1);
TimeSpan winterOffset = tzi.GetUtcOffset(winterDate);
TimeSpan summerOffset = tzi.GetUtcOffset(summerDate);
bool winterIsDst = tzi.IsDaylightSavingTime(winterDate);
bool summerIsDst = tzi.IsDaylightSavingTime(summerDate);
Console.WriteLine("Winter Offset: " + winterOffset + " IsDST: " + winterIsDst);
Console.WriteLine("Summer Offset: " + summerOffset + " IsDST: " + summerIsDst);
输出:
Id: Central Standard Time
DisplayName: (UTC-06:00) Central Time (US & Canada)
StandardName: Central Standard Time
DaylightName: Central Daylight Time
Winter Offset: -06:00:00 IsDST: False
Summer Offset: -05:00:00 IsDST: True
最后,如果您希望能够在任何操作系统上使用任何一组标识符,您可以通过两种不同的方式来处理它:
-
您可以使用我的TimeZoneConverter 库检索TimeZoneInfo。例如:
// Either of these will work on any platform:
TimeZoneInfo tzi = TZConvert.GetTimeZoneInfo("America/Chicago");
TimeZoneInfo tzi = TZConvert.GetTimeZoneInfo("Central Standard Time");
-
您可以使用Noda Time 代替TimeZoneInfo,ZonedDateTimeProviders 用于 Bcl (Windows) 和 Tzdb (IANA) 标识符。
// This will work on any platform:
DateTimeZone dtz = DateTimeZoneProviders.Tzdb["America/Chicago"];
// This will work with Windows on .NET Framework only
DateTimeZone dtz = DateTimeZoneProviders.Bcl["Central Standard Time"];
您可能还想在 Stack Overflow 上阅读 the timezone tag wiki。尤其是标题为“时区数据库”的部分。