Когда я начал работать с часовыми поясами, мне было нелегко, но чем больше я погружался в тему и тем больше терял себя.
В Stack Overflow уже есть десятки похожих вопросов, в основном пытающихся решить конкретные проблемы, но ни один из них (включая ответы) не помог мне понять тему так, как я хотел.
Кроме того, как просили другие, время от времени это выглядит как изменения часового пояса, и Microsoft приходится спешить с обновлениями, распространяемыми через Центр обновления Windows, чтобы справиться с этим.
В моем случае я заметил, что как минимум 2 TZ неверны:
- Алтайское стандартное время
- Стандартное время Аргентины
Поскольку, как я упоминал выше, TZ взяты из локальной системы, я пытался искать обновления, но у меня их нет. Так что либо я действительно упускаю что-то важное, либо Microsoft не заботится об этих двух часовых поясах.
Информация об обновлениях DST / TZ
Для Летнее время , Microsoft имеет четкую политику и заявляет:
Microsoft прилагает усилия для включения этих изменений в Windows и публикует обновление через Центр обновления Windows (WU). Каждое обновление DST / TZ, выпущенное через WU, будет содержать самые последние данные времени, а также будет заменять любое ранее выпущенное обновление DST / TZ
Последние обновления можно найти на специальном сайте Microsoft Tech Community
Чтобы понять, я создал простое консольное приложение (см. Код ниже), проблема в том, что этого было недостаточно.
Обзор наиболее важных классов и методов, использованных в примере
private static ConsoleColor DefaultColor;
static void Main(string[] args)
{
DefaultColor = Console.ForegroundColor;
foreach (var timeZoneInfo in TimeZoneInfo.GetSystemTimeZones().OrderBy(tz => tz.Id))
{
var firstQuart = new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var secondQuart = new DateTime(2019, 4, 1, 0, 0, 0, DateTimeKind.Utc);
var thirdQuart = new DateTime(2019, 7, 1, 0, 0, 0, DateTimeKind.Utc);
var lastQuart = new DateTime(2019, 10, 1, 0, 0, 0, DateTimeKind.Utc);
if (timeZoneInfo.Id == "Altai Standard Time" ||
timeZoneInfo.Id == "Argentina Standard Time" ||
timeZoneInfo.Id == "GMT Standard Time"
)
{
Log($"{timeZoneInfo.DisplayName} (ID: {timeZoneInfo.Id})", ConsoleColor.Yellow);
Log($"StandardName: {timeZoneInfo.StandardName}");
Log($"DST: {timeZoneInfo.SupportsDaylightSavingTime}");
Log($"Daylight Name: {timeZoneInfo.DaylightName}");
Log();
Log($"UTC Offset: {timeZoneInfo.BaseUtcOffset}");
Log($"Dates for each quarter in this year");
var convertedFirstQuart = TimeZoneInfo.ConvertTimeFromUtc(firstQuart, timeZoneInfo);
var convertedSecondQuart = TimeZoneInfo.ConvertTimeFromUtc(secondQuart, timeZoneInfo);
var convertedThirdQuart = TimeZoneInfo.ConvertTimeFromUtc(thirdQuart, timeZoneInfo);
var convertedLastQuart = TimeZoneInfo.ConvertTimeFromUtc(lastQuart, timeZoneInfo);
Log();
Log($"First quarter: {TimeZoneInfo.ConvertTimeFromUtc(firstQuart, timeZoneInfo)}", ConsoleColor.Green);
Log($"DST (DateTime.IsDaylightSavingTime): {convertedFirstQuart.IsDaylightSavingTime()}");
Log($"DST (TimeInfo.IsDaylightSavingTime(DateTime): {timeZoneInfo.IsDaylightSavingTime(convertedFirstQuart)}");
Log($"Ambiguous/Invalid: {timeZoneInfo.IsAmbiguousTime(convertedFirstQuart)}/{timeZoneInfo.IsInvalidTime(convertedFirstQuart)}");
Log();
Log($"Second quarter: {TimeZoneInfo.ConvertTimeFromUtc(secondQuart, timeZoneInfo)}", ConsoleColor.Green);
Log($"DST (DateTime.IsDaylightSavingTime): {convertedSecondQuart.IsDaylightSavingTime()}");
Log($"DST (TimeInfo.IsDaylightSavingTime(DateTime): {timeZoneInfo.IsDaylightSavingTime(convertedSecondQuart)}");
Log($"Ambiguous/Invalid: {timeZoneInfo.IsAmbiguousTime(convertedSecondQuart)}/{timeZoneInfo.IsInvalidTime(convertedSecondQuart)}");
Log();
Log($"Third quarter: {TimeZoneInfo.ConvertTimeFromUtc(thirdQuart, timeZoneInfo)}", ConsoleColor.Green);
Log($"DST (DateTime.IsDaylightSavingTime): {convertedThirdQuart.IsDaylightSavingTime()}");
Log($"DST (TimeInfo.IsDaylightSavingTime(DateTime): {timeZoneInfo.IsDaylightSavingTime(convertedThirdQuart)}");
Log($"Ambiguous/Invalid: {timeZoneInfo.IsAmbiguousTime(convertedThirdQuart)}/{timeZoneInfo.IsInvalidTime(convertedThirdQuart)}");
Log();
Log($"Last quarter: {TimeZoneInfo.ConvertTimeFromUtc(lastQuart, timeZoneInfo)}", ConsoleColor.Green);
Log($"DST (DateTime.IsDaylightSavingTime): {convertedLastQuart.IsDaylightSavingTime()}");
Log($"DST (TimeInfo.IsDaylightSavingTime(DateTime): {timeZoneInfo.IsDaylightSavingTime(convertedLastQuart)}");
Log($"Ambiguous/Invalid: {timeZoneInfo.IsAmbiguousTime(convertedLastQuart)}/{timeZoneInfo.IsInvalidTime(convertedLastQuart)}");
Log("==============================================================");
Log();
}
}
Console.ReadKey();
}
private static void Log(string message = "", ConsoleColor? color = null)
{
if(color.HasValue)
Console.ForegroundColor = color.Value;
Console.WriteLine(message);
Console.ForegroundColor = DefaultColor;
}
}
Учитывая, что мой локальный TZ - GMT, и мы используем DST, вывод будет следующим:
TimeZoneInfo.SupportsDaylightSavingTime () : Официальная документация
В следующем примере извлекается коллекция всех часовых поясов, которые
доступны в локальной системе и отображает имена тех, которые
не поддерживают переход на летнее время.
var zones = TimeZoneInfo.GetSystemTimeZones();
foreach(TimeZoneInfo zone in zones)
{
if (! zone.SupportsDaylightSavingTime)
Console.WriteLine(zone.DisplayName);
}
TimezoneInfo.IsDaylightSavingTime (DateTime) : Официальная документация
Указывает, попадает ли указанная дата и время в диапазон
переход на летнее время для часового пояса текущего TimeZoneInfo
объект.
DateTime.IsDaylightSavingTime () : Официальная документация
Указывает, находится ли этот экземпляр DateTime в дневном свете.
сохранение временного диапазона для текущего часового пояса.
Важно понимать (сначала я этого не делал), что метод IsDaylightSavingTime в экземпляре DateTime всегда возвращает запрошенную информацию с учетом Часовой пояс локальной системы .
Анализировать вывод
Сосредоточив внимание на Аргентине по стандартному времени , мы видим, что TimeZoneInfo.SupportsDaylightSavingTime , возвращают true , это неверная информация, потому что везде, где я искал это, я нашел противоположный результат.
Даже если поддержка DST кажется неправильной, преобразование UTC DateTime в ART TZ с использованием C # всегда дает правильный результат.
Что заставляет меня думать, что я до сих пор не понимаю всю картину здесь, это то, что TimeInfo.IsDaylightSavingTime (DateTime) return false , что я и ожидал.
Постоянное летнее время
Согласно википедии https://en.wikipedia.org/wiki/Daylight_saving_timeПереход к «постоянному переходу на летнее время» (пребывание в летние часы в течение всего года без смены времени) иногда поддерживается и в настоящее время осуществляется в некоторых юрисдикциях, таких как Аргентина, Беларусь, [78] Канада (например, Саскачеван), Исландия, Кыргызстан,Малайзия, Марокко, Намибия, Сингапур, Турция, Туркменистан и Узбекистан. [164] Это может быть результатом следования часового пояса соседнего региона, политической воли или других причин.
Итак, подведу итог, мои открытыевопросы:
- Почему TimezoneInfo.SupportsDaylightSavingTime () return true но TimeInfo.IsDaylightSavingTime (DateTime) return false ?
- Как я могу убедиться, что у меня есть последние обновления DST / TZ от Microsoft, помимо того, что я объяснил выше?