Отримайте часовий пояс від DateTime


103

Чи містить .Net DateTime інформація про часовий пояс, де він створений?

У мене є аналіз бібліотеки DateTime з формату, який має "+ zz" в кінці, і, хоча він правильно розбирає і коригує місцевий час, мені потрібно отримати те, який конкретний часовий пояс був від об'єкта DateTime.

Чи можливо це взагалі? Все, що я бачу, це DateTime.Kind, який вказує, чи час локальний чи UTC.


Дивіться примітки до DateTime.Parse документації для обробки часових поясів та DateTimeStyles. Але ні, те, що ви хочете, насправді неможливо.
yoyo

Відповіді:


136

Сам DateTime не містить реальної інформації про часовий пояс. Він може знати, чи це UTC або локальний, але не те, що місцеве насправді означає.

DateTimeOffset дещо кращий - це в основному час UTC і зміщення. Однак цього все ще недостатньо для визначення часового поясу, оскільки багато різних часових поясів можуть мати однаковий зміщення в будь-який момент часу. Це здається, що це може бути досить добре для вас, хоча все, з чим вам доведеться працювати при розборі дати / часу, - це зсув.

Підтримка часових поясів на .NET 3.5 набагато краща, ніж була, але я дуже хотів би побачити стандартний "ZonedDateTime" або щось подібне - часовий UTC та фактичний часовий пояс. Створити власну легко, але було б непогано побачити це в стандартних бібліотеках.

EDIT: Майже через чотири роки я зараз пропоную використовувати Noda Time, який має досить багатий набір типів дати / часу. Я, як головний автор Noda Time :), упереджений :)


2
Проект PublicDomain на CodePlex робить це за вас.
Cheeso

Перерахунок TimeZone у BCL було б добре, якщо світові часові пояси статичні та не змінюються.
Jeff LaFay

1
@jlafay: Однак вони змінюються - більше минулого року, наприклад, було додано до Windows більше часових поясів.
Джон Скіт

Цей проект вже не підтримується автором; publicdomain.codeplex.com Схоже, що, можливо, це може допомогти, залежно від використання, його потрібно встановити перед його використанням; timezone.codeplex.com
AnneTheAgile

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, який вказує TimeZone пройденого DateTime.

Як зазначають інші, було б непогано, якби Майкрософт став над цим і створив один приємний об’єкт, щоб зробити це все, але поки вам доведеться мати справу з двома об'єктами.


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

Я згоден з Геррі Шенк, будь ласка, прочитайте запропоновану ним статтю.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.