Конвертировать UT C время в местное время страны, которое действительно работает - PullRequest
1 голос
/ 10 января 2020

Если у меня есть время UT C, как мне узнать C# соответствующее местное время в Польше? Или во Франции? Или в Эквадоре? (Я понимаю, что это не имеет смысла для больших стран, таких как Россия, где используется много раз)

В большинстве существующих примеров люди используют объект TimeZoneInfo:

var zone = TimeZoneInfo.FindSystemTimeZoneById("SE Asia Standard Time");

Проблема это не достаточно Во многих странах есть что-то вроде «летнего времени» или « летнего времени », где они используют различное смещение времени по отношению к UT C в зависимости от дня года и даже точного часа (в день изменение времени).

Например, вместо того, чтобы знать, нужна ли мне опция Central Daylight Time или Central Standard Time, я буду знать только, что целевое время для Chica go. Я хочу, чтобы у меня была единственная строка, которая позволила бы платформе решить для меня, какое из этих двух смещений является правильным сейчас.

Существуют ли какие-либо встроенные функции C#, которые занимаются этим, или мне нужно обрабатывать все расчеты, где летнее время начинается и заканчивается согласно закону выбранной страны?

Ответы [ 3 ]

4 голосов
/ 10 января 2020

Если у меня есть время UT C, как мне получить 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 Основные платформы:

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

(Обратите внимание, что Эквадор имеет два часовых пояса , один для материка, один для Галапагосских островов.)

Хорошим ориентиром для определения того, какой Windows ID использовать, является CLDR windowsZones.xml file , который является источником истины для преобразования между Windows и идентификаторами часовых поясов IANA.

(я понимаю, что это не имеет смысла для большого такие страны, как Россия, где используется много раз)

Действительно, в России много различных идентификаторов часовых поясов. Нужно знать, в какой части России они были заинтересованы.

В большинстве существующих примеров люди используют объект TimeZoneInfo:

var zone = TimeZoneInfo.FindSystemTimeZoneById("SE Asia Standard Time");

Проблема в том, что это недостаточно. Во многих странах есть что-то вроде «летнего времени» или « летнего времени », где они используют различное смещение времени по отношению к UT C в зависимости от дня года и даже точного часа (в день изменение времени).

Например, вместо того, чтобы знать, нужен ли мне параметр Central Daylight Time или Central Standard Time, я хочу иметь возможность выбрать America/Chicago и позволить ему справиться с этим для меня.

Нет, это не проблема. Вероятно, вы запутались в требовании, потому что слово «Стандарт» находится в имени идентификатора. Несмотря на это, объект TimeZoneInfo представляет весь часовой пояс, включая как стандартное время, так и летнее / летнее время.

Для пояснения, метод TimeZoneInfo.FindSystemTimeZoneById принимает идентификатор . Свойство Id результирующего объекта будет затем содержать этот идентификатор.

  • "America/Chicago" - это идентификатор часового пояса IANA.
  • "Central Standard Time" является и идентификатором часового пояса Windows, и локализованным Engli sh "стандартным именем" той же зоны (на Windows).
  • "Central Daylight Time" является Engli sh локализованным «именем дневного света» этой зоны (на Windows). Это недопустимый идентификатор часового пояса.

Существуют ли какие-либо встроенные функции C#, которые занимаются этим, или мне нужно обрабатывать все вычисления, где начинается летнее время, и заканчивается в соответствии с законом выбранной страны сам?

Все встроенные вычисления обрабатывают это. Только передайте действительные идентификаторы, и структура будет определять правильное смещение от UT C независимо от того, действует ли стандартное время или летнее / летнее время.

Вот рабочий пример , который демонстрирует эти концепции:

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

Наконец, если вы хотите использовать любой набор идентификаторов в любой операционной системе, есть два различных способа, которыми вы можете обработать это:

  • Вы можете получить TimeZoneInfo с моей библиотекой TimeZoneConverter . Например:

    // Either of these will work on any platform:
    TimeZoneInfo tzi = TZConvert.GetTimeZoneInfo("America/Chicago");
    TimeZoneInfo tzi = TZConvert.GetTimeZoneInfo("Central Standard Time");
    
  • Вы можете использовать Время Noda вместо 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"];
    

Вы также можете прочитать тег часового пояса вики здесь, в Переполнение стека. Особенно в разделе «Базы данных часовых поясов».

2 голосов
/ 10 января 2020

Такие вещи, как переход на летнее время в зависимости от даты. Поэтому, если вы используете часовой пояс для преобразования времени, вы должны предоставить полный DateTime, который вы пытаетесь преобразовать, и. NET будет определять, активен ли DST, и делать соответствующие вычисления.

Следующий пример подчеркивает это: штаты Аризона и Юта находятся в «Горном времени» в США, но Аризона не проводит летнее время, как большинство штатов в США. Таким образом, в зимние месяцы эти два часовых пояса имеют одинаковое смещение, но в летние месяцы они имеют разные смещения.

var arizona = TimeZoneInfo.FindSystemTimeZoneById("US Mountain Standard Time");
var utah = TimeZoneInfo.FindSystemTimeZoneById("Mountain Standard Time");
var time1 = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var time2 = new DateTime(2020, 7, 1, 0, 0, 0, DateTimeKind.Utc);
Console.WriteLine(TimeZoneInfo.ConvertTime(time1, arizona).ToString());
Console.WriteLine(TimeZoneInfo.ConvertTime(time1, utah).ToString());
Console.WriteLine(TimeZoneInfo.ConvertTime(time2, arizona).ToString());
Console.WriteLine(TimeZoneInfo.ConvertTime(time2, utah).ToString());

Выход:

12/31/2019 5 : 00:00:00
31.12.2009 17:00
6/30/2020 5:00:00
30/20/2020 18:00:00

Примечание. С тех пор, как я впервые посмотрел на ваш вопрос, Джоэл Коухорн добавил следующее:

Например, вместо того, чтобы знать, нужна ли мне опция Central Daylight Time или Central Standard Time, Я хочу иметь возможность выбрать America/Chicago и позволить мне справиться с этим.

Я не знаю, было ли это целью вашего вопроса. Если бы это было, это другой вопрос целиком .

1 голос
/ 10 января 2020

Существуют ли какие-либо встроенные функции C#, которые занимаются этим?

К сожалению, нет.

Нужно ли обрабатывать все расчеты, где летнее время начинается и заканчивается согласно закону выбранной страны?

К счастью, также нет. Существует высококачественная библиотека с открытым исходным кодом, которую вы можете использовать под названием NodaTime, и вы можете включить ее в свой проект через NuGet .

Это требует, тем не менее, вы сможете найти правильное имя часового пояса IANA для каждого местоположения (см. столбец «Имя базы данных Tz» в таблице в ссылке).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...