Насколько надежен TimeZoneInfo.GetUtcoffset? - PullRequest
2 голосов
/ 06 ноября 2019

Я использую функцию GetUtcoffset() в TimeZoneInfo объекте, чтобы получить значение смещения Utc для определенной даты и времени. Как правило, переход на летнее время осуществляется по определенному правилу, например « начинается в первое воскресенье октября и заканчивается в первое воскресенье апреля » (стандартное время AUS по восточному времени), поэтому я доверяю полученному результату. Функция производит.

Но мне интересно, что произойдет с результатом, если переход на летнее время будет отложен или изменен по решению правительства? В прошлом было несколько случаев, когда (австралийское) правительство нарушало правила перехода на летнее время для определенных событий. В этих случаях вызовет ли GetUtcoffset() неправильный результат или библиотека будет достаточно умной, чтобы «время от времени» получать обновления для летнего времени из какого-то источника в Интернете?

Использование: Я занимаюсь разработкой системы управления парковкой. Одна база данных используется несколькими клиентами, чей часовой пояс различен. Время парковки может быть использовано в качестве доказательства в суде, поэтому очень важно, чтобы мы поняли это правильно. Когда система получит уведомление о том, что автомобиль припаркован, система сгенерирует время прибытия. Учитывая, что уведомление могло поступить с удаленного сайта в другом часовом поясе, я хотел бы знать, могу ли я надежно использовать часовой пояс для тренировки текущей даты на клиентском сайте.

Пример:

string clientTimeZoneId = "AUS Eastern Standard Time";
var utcTime = DateTime.UtcNow;
var clientTimeZone = TimeZoneInfo.FindSystemTimeZoneById(clientTimeZoneId);
var arrivalTime = utcTime.Add(clientTimeZone.GetUtcOffset(utcTime));

Именно здесь функция GetUtcOffset становится важной. Учитывая, что в 2019–2020 годах переход на летнее время «Восточное стандартное время AUS» завершится 5 апреля 2020 года, вызов GetUtcOffset 6-го числа даст +10: 00: 00. Однако, если по какой-либо причине (например, Олимпийские соревнования), летнее время будет увеличено до 10-го числа, значение arrivalTime может быть неверным на один час в зависимости от значения GetUtcOffset.

В настоящее время наш системный администратор должен ежегодно обновлять дату перехода на летнее время в нашей базе данных вручную, но было бы неплохо, если бы этого не делали. Я не знаю точно, что правительство сделало в этих событиях, но они, должно быть, отправили обновления куда-нибудь, иначе у всех компьютеров в затронутом часовом поясе будет неправильное время. Следовательно, возвращаясь к моему первоначальному вопросу, будет ли TimeZoneInfo получать данные из какого-либо «источника DST»?

1 Ответ

2 голосов
/ 06 ноября 2019

На ваш вопрос есть две части. Я начну с примера кода, который вы дали первым:

var arrivalTime = utcTime.Add(clientTimeZone.GetUtcOffset(utcTime));

Это неправильно применяет смещение. Поскольку utcTime имеет свойство Kind, установленное на DateTimeKind.Utc, то же самое происходит и с результирующим значением после вызова Add. Таким образом, вы не корректируете смещение, а фактически выбираете другой момент времени (10 или 11 часов в будущем). (Для юмористического примера этого см. этот комикс Дильберта .)

Есть несколько различных способов сделать это вместо этого:

  • Выможно использовать методы ConvertTime или ConvertTimeFromUtc на TimeZoneInfo. Полученные дата и время будут такими же, как и раньше, но Kind будет правильно установлен на DateTimeKind.Unspecified.

    DateTime utcNow = DateTime.UtcNow;
    DateTime arrivalTime = TimeZoneInfo.ConvertTime(utcNow, clientTimeZone);
    
  • Вы можете создать DateTimeOffset, используясмещение, которое вы получили:

    DateTimeOffset utcTime = DateTimeOffset.UtcNow;
    DateTimeOffset arrivalTime = utcTime.ToOffset(clientTimeZone.GetUtcOffset(utcTime));
    
  • Вы могли бы легче создать DateTimeOffset, используя TimeZoneInfo.ConvertTime. Это делает то же самое, что и предыдущий код, но чище.

    DateTimeOffset utcTime = DateTimeOffset.UtcNow;
    DateTimeOffset arrivalTime = TimeZoneInfo.ConvertTime(utcTime, clientTimeZone);
    

Для описанного вами сценария я бы рекомендовал использовать DateTimeOffset. У вас будет как местное время, так и смещение от UTC. Храните все это. (Если вы используете что-то вроде Microsoft SQL Server для своей базы данных, вы можете просто использовать одно поле datetimeoffset.)

Хорошая вещь, связанная с местным временем и смещением, заключается в том, что даже если что-тодолжны были измениться, у вас было бы достаточно данных для восстановления фактической точки в универсальном времени, и у вас все еще есть данные в формате, который может быть рационализирован по местному времени. (В качестве альтернативы вы можете хранить как время UTC, так и местное время в двух отдельных полях. Иногда это в любом случае помогает в целях индексации.)

Что касается вашего второго вопроса о надежности данных, я предлагаю прочитать этот вопрос и мой ответ на него. Вообще говоря - да. Данные достоверны. Но давайте распакуем описанный вами сценарий об отклонениях правительства.

  • Прежде всего, вам известны какие-либо такие отклонения, которые уже произошли и которые не записаны в данных часового пояса? Взгляните на историю на timeanddate.com или в источниках базы данных часовых поясов IANA . Если есть отклонения, которые не зарегистрированы, они, вероятно, должны быть. Пожалуйста, отправьте такую ​​информацию в список обсуждения tz . Все остальные узнают об изменениях оттуда.

  • Для Windows вы можете просмотреть данные реестра в HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\AUS Eastern Standard Time\Dynamic DST. См. Исследование часовых поясов Windows ... Сообщение в блоге Microsoft Джоша Фри, чтобы понять, как они работают. Для Сиднея последнее изменение в правилах было зарегистрировано в 2008 году, что соответствует IANA и информации о времени и дате.

  • Имейте в виду, что Windows предполагает, что правила для Сиднея в 2007 году были одинаковыми для всехмоменты времени до этого. У него нет глубины истории, которой обладает база данных IANA. Например, Windows не знает об отклонении от Олимпийских игр 2000 года, о котором говорится в комментарии в базе данных IANA. Если такие исторические изменения важны для вашего приложения, вам нужно будет использовать поставщика TZDB в NodaTime . (Хотя я не могу себе представить, зачем вам нужна эта история для современного приложения парковки.)

Итак, что произойдет, если правительство Австралии решит отклониться в будущем? ?

  • Если они дадут достаточно уведомлений, тогда IANA и Windows получат изменения и распространят их через Центр обновления Windows. Ваш компьютер Windows получит изменение автоматически, и ваше приложение будет правильно учитывать отклонение.

  • Если бы они не не предоставили достаточно уведомлений, то Microsoft следовала бы политике, описанной в aka.ms / time , предоставляя руководство для обходного пути и работая, чтобы получитьизменить так быстро, как это практически возможно. IANA, скорее всего, также ускорит изменение, но время распространения зависит от реализации (Linux, Java, Python, Android, Noda Time и т. Д. Каждый из них распространяет данные часового пояса по-своему.)

Изменения часового пояса с коротким сроком действия действительно произошли в прошлом и являются проблематичными. К счастью, их было меньше в последние годы. Я писал об этом в далеком 2016 году. См .: О времени изменения часового пояса .

TL; DR:

ОтсюдаВозвращаясь к моему первоначальному вопросу, будет ли TimeZoneInfo извлекать данные из любого «источника DST»?

  • Для Windows источником является Microsoft через Windows Updates. Если вы поддерживаете свою систему в актуальном состоянии, то ваше приложение будет иметь правильные данные часового пояса. Такие обновления объявлены в этом блоге .

  • Для .NET, работающей на других платформах (Linux, OSX), конечным источником является часовой пояс IANAбаза данных , данные которой распределяются по используемой платформе. Например, Ubuntu Linux поставляет пакет tzdata с этими обновлениями.

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