Uzyskaj strefę czasową z DateTime

103

Czy .Net DateTime zawiera informacje o strefie czasowej, w której został utworzony?

Mam bibliotekę analizującą DateTime z formatu, który ma na końcu „+ zz” i chociaż analizuje poprawnie i dostosowuje czas lokalny, muszę uzyskać informacje o określonej strefie czasowej z obiektu DateTime.

Czy to w ogóle możliwe? Wszystko, co widzę, to DateTime.Kind, który określa, czy czas jest lokalny, czy UTC.

dbkk
źródło
Zobacz uwagi dotyczące DateTime.Parse dokumentacji dotyczącej obsługi stref czasowych i DateTimeStyles. Ale nie, to, czego chcesz, nie jest naprawdę możliwe.
yoyo

Odpowiedzi:

136

Sama DateTime nie zawiera żadnych informacji o prawdziwej strefie czasowej. To może wiedzieć, czy to UTC lub lokalny, ale nie to, co naprawdę znaczy lokalny.

DateTimeOffset jest nieco lepsza - to po prostu czas UTC i przesunięcie. Jednak to wciąż nie wystarczy do określenia strefy czasowej, ponieważ wiele różnych stref czasowych może mieć takie samo przesunięcie w dowolnym momencie. Wygląda na to, że może ci to wystarczyć, ponieważ wszystko, z czym musisz pracować podczas analizowania daty / godziny, to przesunięcie.

Wsparcie dla stref czasowych od .NET 3.5 jest dużo lepsze niż było, ale naprawdę chciałbym zobaczyć standardowy „ZonedDateTime” lub coś w tym rodzaju - czas UTC i aktualną strefę czasową. Łatwo jest zbudować własne, ale byłoby miło zobaczyć to w standardowych bibliotekach.

EDYCJA: Prawie cztery lata później sugerowałbym teraz użycie czasu Noda, który ma raczej bogatszy zestaw typów daty / czasu. Jestem jednak stronniczy, jako główny autor Noda Time :)

Jon Skeet
źródło
2
Projekt PublicDomain na CodePlex robi to za Ciebie.
Cheeso,
Wyliczenie TimeZone w BCL byłoby przyjemne, gdyby strefy czasowe na świecie były statyczne i nie zmieniają się.
Jeff LaFay
1
@jlafay: Jednak się zmieniają - na przykład więcej stref czasowych zostało dodanych do systemu Windows w zeszłym roku.
Jon Skeet
Ten projekt nie jest już obsługiwany przez autora; publicdomain.codeplex.com Wygląda na to, że ten może pomóc, w zależności od zastosowania, należy go ustawić przed użyciem; timezone.codeplex.com
AnneTheAgile
3
@AnneTheAgile: Osobiście polecam oczywiście korzystanie z mojej własnej biblioteki Noda Time :)
Jon Skeet
36

Nie.

Deweloper jest odpowiedzialny za śledzenie informacji o strefie czasowej skojarzonych z wartością DateTime za pośrednictwem zewnętrznego mechanizmu.

Cytat z doskonałego artykułu tutaj . Lektura obowiązkowa dla każdego programisty .Net.

Więc radzę napisać małą klasę opakowaniową, która odpowiada Twoim potrzebom.

Gerrie Schenck
źródło
2

Możesz użyć klasy TimeZoneInfo

Klasa TimeZone rozpoznaje lokalną strefę czasową i może konwertować czasy między uniwersalnym czasem koordynowanym (UTC) a czasem lokalnym. Obiekt TimeZoneInfo może reprezentować dowolną strefę czasową, a metody klasy TimeZoneInfo mogą służyć do konwertowania czasu w jednej strefie czasowej na odpowiedni czas w dowolnej innej strefie czasowej. Elementy członkowskie klasy TimeZoneInfo obsługują następujące operacje:

  1. Pobieranie strefy czasowej, która jest już zdefiniowana przez system operacyjny.

  2. Wyliczenie stref czasowych, które są dostępne w systemie.

  3. Przeliczanie czasów pomiędzy różnymi strefami czasowymi.

  4. Tworzenie nowej strefy czasowej, która nie została jeszcze zdefiniowana przez system operacyjny.

    Serializowanie strefy czasowej do późniejszego pobrania.

Shekhar
źródło
1
... ale biorąc pod uwagę DateTime, nadal nie ma sposobu, aby użyć TimeZoneInfo do określenia TimeZone DateTime, o ile wiem.
Remi Despres-Smyth
@ RemiDespres-Smyth Po prostu przechowuję TimeZoneInfo wraz z DateTime w 1 klasie.
Konrad
0

Ogólnie praktyką byłoby przekazywanie danych jako DateTime z „strefą czasową” UTC, a następnie przekazywanie obiektu TimeZoneInfo, a gdy jesteś gotowy do wyświetlenia danych, możesz użyć obiektu TimeZoneInfo do przekonwertowania UTC DateTime.

Inną opcją jest ustawienie DateTime z bieżącą strefą czasową, a następnie upewnij się, że „strefa czasowa” jest nieznana dla obiektu DateTime, a następnie upewnij się, że DateTime jest ponownie przekazywana z TimeZoneInfo, która wskazuje TimeZone z DateTime.

Jak wskazywali inni, byłoby miło, gdyby Microsoft do tego doszedł i stworzył jeden fajny obiekt, aby zrobić to wszystko, ale na razie musisz poradzić sobie z dwoma obiektami.

Obrabować
źródło
0

DateTime nie zna swojego przesunięcia w strefie czasowej. Nie ma wbudowanej metody zwracania przesunięcia lub nazwy strefy czasowej (np. EAT, CEST, EST itp.).

Jak sugerowali inni, możesz przekonwertować swoją datę na UTC:

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

a potem tylko oblicz różnicę:

TimeSpan difference = localtime - utctime;

Możesz również przekonwertować jeden raz na inny za pomocą DateTimeOffset:

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

Ale jest to rodzaj stratnej kompresji - samo przesunięcie nie może powiedzieć, która to strefa czasowa, ponieważ dwa różne kraje mogą znajdować się w różnych strefach czasowych i mieć ten sam czas tylko przez część roku (np. RPA i Europa). Należy również pamiętać, że letni czas letni może zostać wprowadzony w różnych terminach (EST vs CET - różnica 3 tygodni).

Nazwę lokalnej strefy czasowej systemu można uzyskać za pomocą klasy TimeZoneInfo:

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

Zgadzam się z Gerrie Schenck, przeczytaj artykuł, który zasugerował.

henryalligator
źródło