Najlepsza praktyka do przechowywania DateTime na podstawie TimeZone


16

Opracowanie aplikacji internetowej, która powinna umożliwić Użytkownikowi planowanie spotkania w oparciu o strefę czasową. Przechowuję zaplanowaną przez użytkownika datę i godzinę jako datę i godzinę serwera w polu bazy danych. Podczas wyświetlania informacji o harmonogramie pobrano wartość z bazy danych i przekonwertowano na strefę czasową użytkownika. Przetwarzanie w bazie kodu Konwertuję DateTime na podstawie strefy czasowej użytkownika. Proszę zasugerować, czy jest to najlepsza praktyka, czy istnieje jakiś łatwy sposób?

Odpowiedzi:


33

Witamy w jednym z najtrudniejszych problemów w programowaniu bez obliczeń - prawidłowym przedstawianiu dat i godzin użytkownikom końcowym.

Realistycznie znaczniki czasu powinny być przechowywane w stałej pojedynczej reprezentacji, niezależnie od tego, jak będą interpretowane, ponieważ bez względu na to, jak bardzo się starasz, zawsze będziesz miał niejednoznaczne przypadki i nie możesz rozwiązać ich bez stałej reprezentacji. Wybrałeś jeden z najgorszych przypadków użycia - umówienie spotkania. Jedynym gorszym przypadkiem powszechnego użycia są podróże lotnicze, w których podróż może rozpocząć się w jednej strefie czasowej, a skończyć w innej, możliwe we wcześniejszym czasie lokalnym.

Zawsze, zawsze, ZAWSZE przechowuj w UTC i wyświetlaj w preferowanej lub wyraźnie określonej strefie czasowej użytkownika. Jeśli to w ogóle możliwe, poproś użytkownika o wskazanie strefy czasowej, w której wierzy on, kiedy jest wprowadzany ( np. Mieć wyraźne pole strefy czasowej i wstępnie wypełnić ją preferowaną strefą).


1
+1. I jest elastyczny. Posiadanie wspólnego, spójnego, uniwersalnego standardowego czasu odniesienia - każda lokalna „dereferencja” strefy zostanie wykonana poprawnie.
radarbob

W rzeczywistości planowanie spotkania jest jednym z kilku przypadków, w których możesz nie zapisać go jako UTC: jeśli zmieniają się reguły DST (lub przesunięcie w stosunku do UTC), co dzieje się z czasem spotkania? W większości przypadków chcesz, aby czas spotkania pozostał taki sam lokalnie, co oznacza zmianę wartości UTC. Najprawdopodobniej chcesz zapisać wartość reprezentującą „TimeInTimeZone + TimeZone”, z której można łatwo uzyskać UTC. Harmonogramowanie w różnych strefach czasowych (np. Linie lotnicze) ma ograniczenia, które prawdopodobnie oznaczają połączenie obu tych opcji.
Clockwork-Muse,

1
Och, robi się coraz gorzej. Regularnie spotykam się z kolegami z innych narodów, których zasady zmiany czasu różnią się od moich. Kiedy tak się stanie, jaka jest prawidłowa odpowiedź? Właściwie żaden komputer nie wie :-(
Ross Patterson

3

Najłatwiejszy sposób radzenia sobie z informacjami o dacie / godzinie zależy od wymagań aplikacji.

Jeśli data i godzina zostaną wprowadzone przez użytkownika, a serwer nie przetwarza danych z tą datą / godziną, oprócz przechowywania ich w bazie danych i nie należy oczekiwać, że wprowadzony czas zostanie dostosowany do lokalizacji, w której jest przeglądany (na przykład , użytkownik wprowadził „20:00” i powinien być wyświetlany jako „20:00” bez względu na to, gdzie na świecie jest oglądany), wówczas najłatwiejszym sposobem jest zapisanie daty i godziny jako czasu lokalnego bez żadnych informacji o strefie czasowej.

Z drugiej strony, jeśli serwer musi użyć wprowadzonego DateTime jako wyzwalacza, aby coś zrobić, lub jeśli czas powinien być odpowiednio dostosowany do bieżącej strefy czasowej, wtedy najlepszą opcją jest zapisanie DateTime jako czasu UTC i dostosowanie go do lokalnego czas (dla bieżącej lokalizacji użytkownika) za każdym razem, gdy czytasz ją z bazy danych.


-1 dla „przechowuj w czasie lokalnym”, +1 dla „przechowuj w UTC”.
Ross Patterson

@RossPatterson: Czy możesz wyjaśnić swoje „-1” dla „przechowuj w czasie lokalnym”? Jestem ciekawy, dlaczego to zły pomysł, biorąc pod uwagę warunki, które mu dałem.
Bart van Ingen Schenau

1
Na przykład użycie czasu lokalnego użytkownika oznacza, że ​​każda wartość jest faktycznie jednym z kilkudziesięciu różnych typów danych. Co oznacza, że ​​nie można interesująco wykonywać na nich operacji bazy danych, takich jak „TIMESTAMP> '2013-08-27T12: 00: 00'”. Oznacza to nawet, że nie wiesz, kiedy i czy zastosować konwersje czasu letniego.
Ross Patterson

@RossPatterson: Dziękuję. Zgadzam się, że czas lokalny w większości przypadków nie jest właściwym rozwiązaniem.
Bart van Ingen Schenau

2

Ważne jest, aby nie łączyć dwóch powiązanych pojęć.

Jeśli manipulujesz faktycznym momentem w czasie, czyli określonym czasem w określonym dniu, jedynym sposobem na to jest zawsze użycie uniwersalnej wartości czasu UTC. Nigdy nie próbuj przechowywać tego jako wartości odpowiedniej dla strefy czasowej. Wyświetlając tę ​​wartość czasu użytkownikowi, zawsze należy konwertować na strefę czasową użytkownika w tym czasie. (I nie zapomnij, że zarówno godzina, jak i data zależą od strefy czasowej).

Inna koncepcja to „wyrażenie czasu”, takie jak „20:00 w każdy wtorek”. W szczególności wspomniałeś o umożliwieniu ludziom planowania spotkań, a jeśli masz spotkania cykliczne, potrzebujesz takiego wyrażenia. Nie znam żadnego standardowego języka wyrażeń, ale cokolwiek użyjesz, będzie ono zależne od strefy czasowej osoby, która go określiła. Najlepiej byłoby to wyrazić np. „20.00 w każdy wtorek w strefie czasowej Pacyfiku”. W przypadku wyrażenia czasu, przechowujesz je zawsze jako ciąg i nigdy nie angażujesz żadnych formatów czasu systemowego.

Zobacz więcej dyskusji na ten temat na moim blogu


1

Wiele odpowiedzi tutaj wskazuje na przechowywanie jako UTC. Ale bądź z tym bardzo ostrożny. Na przykład, jeśli umówisz się na spotkanie o godzinie 12:00, ale spotkanie odbędzie się po zmianie na czas letni, co się stanie? UTC nie przechowuje żadnych informacji o tym, czy dst było aktywne, gdy spotkanie było przechowywane. Wiele dużych, znanych systemów popełniło ten błąd, gdy użytkownik wysyła wiadomość e-mail o 9 rano latem, a następnie zimą wysłany czas pokazuje 8 rano, ponieważ obliczenia z UTC zależą od tego, kiedy spojrzysz na godzinę, nie jest włączony, kiedy data / godzina została zarejestrowana.

Znacznie lepiej jest założyć, że użytkownik chce mieć zawsze wybrane czasy. Bez konwersji UTC, bez konwersji czasu, bez informacji o strefie czasowej, nic. Umówienie się na spotkanie od 08:00 do 12:00 w dniu 21 marca 2016 r. Jest właśnie takie. Nie używaj czasu lokalnego ani czasu UTC, ale czas nieokreślony (w jsonie nie ma ani Z ani +, w zasadzie w .NET ma DateTime.Kind = DateTimeKind.Unspecified).

Oczywiście, jeśli twoim przypadkiem użycia jest to, że jesteś firmą, która odbywa spotkania z kimś z różnych stref czasowych i chcesz zobaczyć te informacje, powiedzmy, w kalendarzu firmowym, ale pozwolić użytkownikom zobaczyć, która godzina jest w ich strefie czasowej, staje się bardziej skomplikowane. Czas musi być odpowiedni dla różnych osób w różnych strefach czasowych (dostawca i klient).

W takich przypadkach możesz nawet chcieć zapisać, kiedy spotkanie zostało zapisane w bazie danych, w której strefie czasowej i jeśli zawierało to dst, czy nie. W ten sposób zawsze możesz obliczyć czas lokalny na cokolwiek innego, czy to będzie teraz, czy to, co miało być historycznie. Ponieważ strefy czasowe są bardzo niestatyczne, co jeszcze bardziej komplikuje sytuację.

Na szczęście w tym miejscu przychodzą biblioteki takie jak http://nodatime.org/ i są wysoce zalecane. Działają z datami znacznie bardziej konsekwentnie. Nawet wtedy zaleciłbym zawinięcie wszystkich zmiennych i logiki datetime w swoje własne opakowania, używając interfejsów, aby można było ich wyśmiewać, a następnie można zmienić logikę później.


Nie do końca zgadzam się z waszymi wnioskami, ale spotkanie w południe zaplanowane na zmianę oszczędności w ciągu dnia jest szczególnym wyzwaniem, podobnie jak cotygodniowe spotkanie zarezerwowane na kilka lat w przyszłości.
Wygięty

Oczywiście, jeśli Twoim przykładem użycia jest to, że jesteś firmą, która odbywa spotkania z kimś z różnych stref czasowych i chcesz zobaczyć te informacje, powiedzmy, w kalendarzu firmowym, ale pozwolić użytkownikom zobaczyć, która godzina jest w ich strefie czasowej, robi się bardziej skomplikowane. ”- to prawie każda firma. Bardzo niewiele firm spoza Chin i Indii może zignorować spotkania w różnych strefach czasowych.
Ross Patterson

W ten sposób zawsze możesz obliczyć czas lokalny na cokolwiek innego, albo to, co byłoby teraz, albo to, co miało być historycznie. Ponieważ strefy czasowe są bardzo niestatyczne, co jeszcze bardziej komplikuje sytuację. ” - raz akceptujesz, że zamierzasz wykonać obliczenia, naprawdę musisz wybrać jedną reprezentację czasu. UTC, EST (ale nie EST5EDT), IST, cokolwiek. Ale po prostu nie możesz mieć wartości opartych na wielu strefach czasowych w tym samym polu i wykonywać na nich uzasadnionego przetwarzania zbiorczego. Przetwarzanie wyświetlania, jasne. Ale to jest łatwa część.
Ross Patterson

Przynajmniej nadal możesz poprawnie przekonwertować na UTC. Zawsze możesz utworzyć tabelę obliczeniową lub wartość na podstawie tych informacji z perspektywy czasu. Ale nigdy nie możesz iść w drugą stronę. Zauważ, że SQL 2016 zaczyna obsługiwać to natywnie, choć niestety nadal opiera się na - przynajmniej historycznie - niezupełnie poprawnych danych rejestru - ale to kolejna poprawa.
Arwin,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.