Получить часовой пояс из DateTime

103

Содержит ли .Net DateTime информацию о часовом поясе, в котором он был создан?

У меня есть библиотека, анализирующая DateTime из формата, в конце которого есть "+ zz", и, хотя она правильно анализирует и регулирует местное время, мне нужно получить конкретный часовой пояс из объекта DateTime.

Это вообще возможно? Все, что я вижу, это DateTime.Kind, который указывает, является ли время местным или UTC.

dbkk
источник
См. Примечания к документации DateTime.Parse для обработки часовых поясов и DateTimeStyles. Но нет, то, чего вы хотите, на самом деле невозможно.
yoyo

Ответы:

137

Сама DateTime не содержит информации о часовом поясе в реальном времени. Он может знать, является ли это UTC или местным, но не то, что на самом деле означает местный.

DateTimeOffset несколько лучше - это время в формате UTC и смещение. Однако этого все еще недостаточно для определения часового пояса, поскольку многие разные часовые пояса могут иметь одинаковое смещение в любой момент времени. Похоже, это может быть достаточно для вас, поскольку все, с чем вам нужно работать при синтаксическом анализе даты / времени, - это смещение.

Поддержка часовых поясов в .NET 3.5 намного лучше, чем была, но мне бы очень хотелось увидеть стандартный «ZonedDateTime» или что-то в этом роде - время в формате UTC и фактический часовой пояс. Самостоятельно собрать несложно, но было бы неплохо увидеть это в стандартных библиотеках.

РЕДАКТИРОВАТЬ: почти четыре года спустя я бы предложил использовать Noda Time, который имеет довольно богатый набор типов даты / времени. Но я пристрастен, как главный автор Noda Time :)

Джон Скит
источник
2
Проект PublicDomain на CodePlex сделает это за вас.
Cheeso,
Перечисление TimeZone в BCL было бы неплохо, если бы часовые пояса мира были статичными и не менялись.
Джефф ЛаФэй
1
@jlafay: Однако они меняются - например, в прошлом году в Windows было добавлено больше часовых поясов.
Джон Скит,
Этот проект больше не поддерживается автором; publicdomain.codeplex.com Кажется, что это может помочь, в зависимости от использования, его нужно установить перед использованием; timezone.codeplex.com
AnneTheAgile 09
3
@AnneTheAgile: Лично я бы порекомендовал использовать свою собственную библиотеку Noda Time, конечно :)
Джон Скит,
36

Нет.

Разработчик отвечает за отслеживание информации о часовом поясе, связанной со значением DateTime, через некоторый внешний механизм.

Цитата из отличной статьи здесь . Обязательно к прочтению каждому разработчику .Net.

Итак, мой совет - написать небольшой класс-оболочку, который соответствует вашим потребностям.

Герри Шенк
источник
2

Вы можете использовать класс TimeZoneInfo

Класс TimeZone распознает местный часовой пояс и может преобразовывать время между всемирным координированным временем (UTC) и местным временем. Объект TimeZoneInfo может представлять любой часовой пояс, а методы класса TimeZoneInfo могут использоваться для преобразования времени в одном часовом поясе в соответствующее время в любом другом часовом поясе. Члены класса TimeZoneInfo поддерживают следующие операции:

  1. Получение часового пояса, который уже определен операционной системой.

  2. Перечисление часовых поясов, доступных в системе.

  3. Преобразование времени между разными часовыми поясами.

  4. Создание нового часового пояса, который еще не определен операционной системой.

    Сериализация часового пояса для последующего использования.

Шехар
источник
1
... но, учитывая DateTime, насколько мне известно, по-прежнему нет способа использовать TimeZoneInfo для определения TimeZone DateTime.
Реми Депре-Смит,
@ RemiDespres-Smyth Я просто храню TimeZoneInfo вместе с DateTime в 1 классе.
Конрад
0

Обычно практика заключается в передаче данных как DateTime с «часовым поясом» UTC, а затем в передаче объекта TimeZoneInfo, и когда вы будете готовы отобразить данные, вы используете объект TimeZoneInfo для преобразования UTC DateTime.

Другой вариант - установить DateTime с текущим часовым поясом, а затем убедиться, что «часовой пояс» неизвестен для объекта DateTime, а затем убедиться, что DateTime снова передается с TimeZoneInfo, который указывает часовой пояс переданного DateTime.

Как указывали здесь другие, было бы неплохо, если бы Microsoft взялась за это и создала один хороший объект для всего этого, но пока вам придется иметь дело с двумя объектами.

Роб
источник
0

DateTime не знает смещения своего часового пояса. Нет встроенного метода для возврата смещения или имени часового пояса (например, EAT, CEST, EST и т. Д.).

Как было предложено другими, вы можете преобразовать дату в UTC:

DateTime localtime = new DateTime.Now;
var utctime = localtime.ToUniversalTime();

а потом только рассчитать разницу:

TimeSpan difference = localtime - utctime;

Также вы можете преобразовать одно время в другое, используя DateTimeOffset:

DateTimeOffset targetTime = DateTimeOffset.Now.ToOffset(new TimeSpan(5, 30, 0));

Но это своего рода сжатие с потерями - одно только смещение не может сказать вам, в каком часовом поясе он находится, поскольку две разные страны могут находиться в разных часовых поясах и иметь одно и то же время только в течение части года (например, Южная Африка и Европа). Также имейте в виду, что летнее время может вводиться в разные даты (EST и CET - разница в 3 недели).

Вы можете получить название часового пояса вашей локальной системы, используя класс TimeZoneInfo:

TimeZoneInfo localZone = TimeZoneInfo.Local;
localZone.IsDaylightSavingTime(localtime) ? localZone.DaylightName : localZone.StandardName

Я согласен с Джерри Шенком, прочтите, пожалуйста, статью, которую он предложил.

Генриаллигатор
источник