Przechowywanie DateTime (UTC) a przechowywanie DateTimeOffset

96

Zwykle mam "przechwytywacz", który tuż przed odczytem / zapisem z / do bazy danych dokonuje konwersji DateTime (z UTC na czas lokalny iz czasu lokalnego na UTC), więc mogę używać DateTime.Now(derywacji i porównań) w całym systemie bez obaw o strefach czasowych.

Jeśli chodzi o serializację i przenoszenie danych między komputerami, nie trzeba się tym przejmować, ponieważ data i godzina to zawsze UTC.

Czy powinienem nadal przechowywać moje daty (SQL 2008 - datetime) w formacie UTC, czy zamiast tego powinienem przechowywać je przy użyciu DateTimeOffset(SQL 2008 - datetimeoffset)?

Daty UTC w bazie danych (typ datetime) działają i są znane od tak dawna, po co to zmieniać? Jakie są zalety?

Przeglądałem już artykuły takie jak ten , ale nie jestem w 100% przekonany. jakieś pomysły?

Frederico
źródło
Powiązane pytanie: stackoverflow.com/questions/2532729/…
Oded
1
Zobacz też: DateTime vs DateTimeOffset - napisane dla .Net, ale koncepcyjnie dotyczy również SQL.
Matt Johnson-Pint,

Odpowiedzi:

131

Jest jedna ogromna różnica, w której nie można używać samego UTC.

  • Jeśli masz taki scenariusz

    • Jeden serwer i kilku klientów (wszyscy geograficznie w różnych strefach czasowych )
    • Klienci tworzą pewne dane z informacjami o dacie i godzinie
    • Klienci przechowują to wszystko na serwerze centralnym
  • Następnie:

    • datetimeoffset przechowuje lokalny czas klienta i RÓWNIEŻ przesunięcie względem czasu UTC
    • wszyscy klienci znają czas UTC wszystkich danych, a także czas lokalny w miejscu, z którego pochodzą informacje
  • Ale:

    • Data UTC przechowuje tylko datę UTC , więc nie masz informacji o czasie lokalnym w lokalizacji klienta, z której pochodzą
    • Inni klienci nie znają czasu lokalnego w miejscu, z którego pochodzą informacje o datach i godzinach
    • Inni klienci mogą obliczyć tylko swój czas lokalny z bazy danych (przy użyciu czasu UTC), a nie czas lokalny klienta, z którego pochodzą dane

Prostym przykładem jest system rezerwacji biletów lotniczych ... Bilet lotniczy powinien zawierać 2 godziny: - czas „startu” (w strefie czasowej miasta „From”) - czas „lądowania” (w strefie czasowej miasta „Destination”)

Marcel Toth
źródło
2
To najlepsze wyjaśnienie, o jakim czytałem, kiedy byłoby właściwe, a dużo czytałem. Dla nas z tego nie wydaje się. Otrzymujemy czas w UTC dla naszych danych zewnętrznych iw razie potrzeby znamy lokalizację z innego źródła (i nigdy nie było). Dzięki, że sprawiłeś, że wydaje się to takie oczywiste.
Andrew Backer,
19
powiedziałeś "datetimeoffset przechowuje czas UTC i RÓWNIEŻ przesunięcie względem lokalnego czasu klienta", ale datetimeoffset przechowuje LOKALNY czas + przesunięcie lub czas UTC + przesunięcie równe +0.
Serhii Kyslyi
chociaż możesz po prostu rzucić DTO na DT, ponieważ podstawą DT jest UTC (chociaż byłby to dodatkowy krok dla wszystkich korzystających z bazy danych i prawdopodobnie nie jest prostszy niż użycie samego czasu UTC)
iliketocode
2
Wygląda na to, że DateTmeOffset przechowuje „Czas lokalny i przesunięcie UTC”, a nie „Czas UTC i przesunięcie UTC”. Jeśli rzutujesz na datę / godzinę lub używasz którejkolwiek z funkcji datepart, otrzymasz lokalne składniki daty i godziny.
Triynko,
wszyscy klienci znają czas UTC wszystkich danych, a także czas lokalny w miejscu, z którego pochodzą informacje”. Chociaż przechowywanie w polu daty wydaje się w tym przypadku nienormalne. Jaki jest przypadek użycia - to znaczy, dlaczego nie miałbyś użyć UTC i wyciągnąć przesunięcia do InputLocationId(lub podobnej znormalizowanej jednostki). Wymagałoby to obliczeń (cześć, wyjątki ... szczególnie ty, Indiana ), ale nadal jest to proces deterministyczny - a wtedy równowaga logiki daty i godziny aplikacji jest prosta.
ruffin
23

Masz absolutną rację, używając UTC dla wszystkich czasów historycznych (tj. Nagrywanie wydarzeń). Zawsze można przejść z UTC do czasu lokalnego, ale nie zawsze na odwrót.

Kiedy używać czasu lokalnego? Odpowiedz na to pytanie:

Jeśli rząd nagle zdecyduje się na zmianę czasu letniego, czy chciałbyś, aby te dane zmieniły się wraz z nim?

Przechowuj czas lokalny tylko wtedy, gdy odpowiedź brzmi „tak”. Oczywiście będzie to dotyczyło tylko przyszłych dat i zwykle tylko dat, które mają jakiś wpływ na ludzi.

Po co przechowywać strefę czasową / przesunięcie?

Po pierwsze, jeśli chcesz zarejestrować przesunięcie dla użytkownika, który wykonał akcję, prawdopodobnie najlepiej będzie to zrobić, tj. Podczas logowania zapisz lokalizację i strefę czasową tego użytkownika.

Po drugie, jeśli chcesz przekonwertować do wyświetlania, musisz mieć tabelę wszystkich lokalnych przejść przesunięcia czasu dla tej strefy czasowej, po prostu wiedząc, że bieżące przesunięcie nie wystarczy, ponieważ jeśli pokazujesz datę / godzinę sprzed sześciu miesięcy, przesunięcie będzie być innym.

Ben
źródło
4
Konwersja czasu UTC w systemie Windows na czas lokalny uwzględnia zmiany czasu letniego dla dat historycznych. Nie rozumiem, dlaczego chcesz w takim przypadku przechowywać czas lokalny.
Jamiegs
1
@Jamiegs Windows historycznie zna tylko „ostatnie informacje historyczne” (jak wskazano / odnotowano w dokumentacji .NET DateTime). Nie jest wyczerpująca.
2
oczywiście musisz również zapisać lokalizację zdarzenia, w przeciwnym razie nie możesz powiedzieć, w jakim „czasie lokalnym” zdarzenie miało miejsce.
keuleJ
20

DATETIMEOFFSET daje możliwość przechowywania czasu lokalnego i czasu UTC w jednym polu.

Pozwala to na bardzo proste i wydajne raportowanie w czasie lokalnym lub UTC bez konieczności przetwarzania danych do wyświetlania w jakikolwiek sposób.

Są to dwa najczęstsze wymagania - czas lokalny dla raportów lokalnych i czas UTC dla raportów grupowych.

Czas lokalny jest przechowywany w części DATETIME w DATETIMEOFFSET, a OFFSET z UTC jest przechowywany w części OFFSET, dzięki czemu konwersja jest prosta, a ponieważ nie wymaga znajomości strefy czasowej, z której pochodzą dane, można to zrobić na poziomie bazy danych .

Jeśli nie potrzebujesz czasu do milisekund, np. Tylko do minut lub sekund, możesz użyć DATETIMEOFFSET (0). Pole DATETIMEOFFSET będzie wtedy wymagało tylko 8 bajtów pamięci - tyle samo, co DATETIME.

Stosowanie DATETIMEOFFSET zamiast UTC DATETIME zapewnia zatem większą elastyczność, wydajność i prostotę raportowania.

PapillonUK
źródło
Struktura zbyt złej jednostki nie ma żadnego sposobu na uzyskanie dostępu do lokalnej daty i godziny pola datetimeoffset, co uniemożliwia zapytanie o konkretną datę lokalną.
Triynko,
@Triynko, czy możesz wyjaśnić, co masz na myśli? Przykład?
reidLinden