Резюме
Вы не можете знать, потому что, не сохраняя смещение, вы потеряли важную часть информации, часовой пояс, в котором изначально было время, которое, как вы указали, может быть либо по восточному стандартному времени, либо по восточному дневному свету. Время.
Обнаружение неоднозначного времени
TimeZoneInfo предоставляет метод IsAmbiguousTime , чтобы проверить, может ли это быть так.
Проблема с вашим обнаружением в течение этого неоднозначного времени заключается в том, что вы пытаетесь использовать IsDaylightSavings
, который возвращает ложное значение для неоднозначных времен, как показано в этом примере:
var est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var times = new DateTime[] {
new DateTime (2010, 11, 7, 4, 0, 0, DateTimeKind.Utc),
new DateTime (2010, 11, 7, 5, 0, 0, DateTimeKind.Utc),
new DateTime (2010, 11, 7, 5, 30, 0, DateTimeKind.Utc),
new DateTime (2010, 11, 7, 6, 0, 0, DateTimeKind.Utc),
};
Console.WriteLine(" Time | IsDaylightSaving | IsAmbiguousTime");
foreach (var t in times) {
var time = TimeZoneInfo.ConvertTimeFromUtc(t, est);
Console.WriteLine (" {0:HH:mm} | {1,11} | {2,5}", time, est.IsDaylightSavingTime(time), est.IsAmbiguousTime(time));
}
Результат:
Time | IsDaylightSaving | IsAmbiguousTime
00:00 | True | False
01:00 | False | True
01:30 | False | True
01:00 | False | True
Итак, вы хотите использовать est.IsAmbiguousTime(EasternTime)
. Тогда нет необходимости в DuplicateHour
, поскольку это будет охватывать весь временной диапазон, который неоднозначен в тот день.
DateTimeOffset не страдает этой проблемой из-за явного сохранения смещения.
Преобразование EST в UTC и сохранение в базе данных
Для вашего первоначального преобразования из EST в UTC существующие данные в базе данных захотят сохранить смещение для будущего использования. Для не неоднозначных времен это может быть получено из часового пояса. Однако, как вы определили, для неоднозначных времен эта информация будет недоступна. Для этих времен вам придется предположить, какое смещение использовать, и пометить время в БД как подозрительное, чтобы пользовательский интерфейс мог соответствующим образом реагировать при отображении этих времен.
В зависимости от того, на какое количество данных влияют, может не стоить усилий изменить пользовательский интерфейс и просто проигнорировать проблему, особенно если это действительно не так важно для пользователя, если время истекло на час (так как на экране пользователя в этом часовом поясе он будет отображаться как 1:00). БД все равно запишет, что время было подозрительным, если вы когда-нибудь потом передумали.
Преобразование из UTC в EST и обнаружение неоднозначного времени
Во-первых, используйте DateTimeOffset, так как это может показать разницу между 1:00 EST и 1:00 EDT. В этот момент TimeZoneInfo.IsAmbiguousTime(DateTimeOffset)
может использоваться для выделения дублированного времени на экране, а TimeZoneInfo.IsDaylightSavings(DateTimeOffset)
также будет правильно возвращать true или false.
var est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var times = new DateTimeOffset[] {
new DateTimeOffset (2010, 11, 7, 4, 00, 0, TimeSpan.Zero),
new DateTimeOffset (2010, 11, 7, 5, 00, 0, TimeSpan.Zero),
new DateTimeOffset (2010, 11, 7, 5, 30, 0, TimeSpan.Zero),
new DateTimeOffset (2010, 11, 7, 6, 00, 0, TimeSpan.Zero),
};
Console.WriteLine(" Time | IsDaylightSaving | IsAmbiguousTime");
foreach (var t in times) {
var time = TimeZoneInfo.ConvertTime (t, est);
Console.WriteLine (" {0:HH:mm} | {1,11} | {2,5}", time, est.IsDaylightSavingTime(time), est.IsAmbiguousTime(time));
}
Результат:
Time | IsDaylightSaving | IsAmbiguousTime
00:00 | True | False
01:00 | True | True
01:30 | True | True
01:00 | False | True
Будущие соображения
Проблемы с пользовательским интерфейсом
При отображении пользователю не должно иметь значения, является ли местное время неоднозначным или нет (дублированный час). Вы можете просто преобразовать время UTC в их часовой пояс и отформатировать в виде строки. Возможно, вы захотите проверить IsAmbiguousTime, чтобы отобразить подсказку для пользователя, почему он может видеть «1:00» дважды. Сортировка информации по дате должна производиться с использованием UTC. Переход от UTC к местному времени никогда не должен быть неоднозначным, поскольку каждый момент времени существует только один раз в UTC, повторяющихся часов нет.
Так что единственная проблема сейчас, это если пользователь вводит время, и вам нужно интерпретировать, какое время они имели в виду, так как пользователь вряд ли введет смещение или даже будет заботиться о таких деталях. К сожалению, не существует простого способа справиться с этим, кроме как попытаться научить ваших пользователей о смещениях, они будут ошибаться и вводить неправильное время. Например, они могут войти в 4 часа утра, думая о 4 часах после полуночи, забыв о том, что в эту ночь есть 1 час больше / меньше. В качестве альтернативы они могут войти в 3 часа ночи в день, когда часы идут вперед в 3 часа ночи, что в этот день просто не существует.
К счастью, время смены часов направлено на то, чтобы свести к минимуму проблему пользовательского ввода, поскольку большинство людей спят. Таким образом, система могла бы сделать правильный выбор и принять время на время от времени. Если это действительно имеет значение, вы можете проверить, есть ли в этот день летнее время, и показать другой пользовательский интерфейс с предупреждением / подсказкой.
Хранение и передача
При хранении времени на сервере MSSQL предпочтение отдается datetimeoffset , поскольку оно может обрабатывать как время, так и смещение. При использовании этого типа MSSQL-сервер может корректно обрабатывать время сравнения с различными смещениями.
Для баз данных, которые не поддерживают такой тип, вы можете сохранить время в UTC в базе данных и сохранить смещение для этого времени в отдельном столбце. Это позволит вам точно знать местное время, в которое оно было записано.
При обмене с внешними системами, в идеале, следует передавать местное время в формате yyyy-MM-dd HH:mm:sszzzz
(например, 2010-11-07 01:00:00-03:30
), чтобы можно было сохранить как время, так и смещение. В противном случае UTC обычно является лучшим выбором, но в идеале должно быть добавлено суффикс «Z» или «+00: 00», чтобы сделать это очевидным.
В памяти класс DateTimeOffset является лучшим выбором, поскольку он может представлять любое произвольное смещение по сравнению с DateTime, которое может представлять только UTC или местное время системы.
Обратите внимание, что точность летнего времени TimeZoneInfo зависит от версии ОС, пакетов обновления и примененных обновлений Windows.
Кроме того, важно, как применяется летнее время. Если они применяются ОС с использованием «Автоматически настраивать часы для перехода на летнее время», тогда смещение будет корректно отрегулировано. Если администратор отключил это и вручную настраивает время, добавляя / вычитая час, ОС не узнает об этом и будет работать с неправильным смещением. См. TimeZoneInfo.Local для других примечаний относительно этой настройки ОС.