Jaki jest prawidłowy przypadek użycia TIMESTAMP BEZ STREFY CZASOWEJ?

40

Istnieje długa i dość wyjaśniająca odpowiedź na temat różnic między nimi

  • TIMESTAMP WITH TIME ZONE -vs-
  • TIMESTAMP WITHOUT TIME ZONE

dostępne w tym poście SO . Chciałbym wiedzieć: czy istnieją jakieś ważne przypadki użycia do faktycznego użycia, TIMESTAMP WITHOUT TIME ZONEczy też należy to uznać za anty-wzór.

Marcus Junius Brutus
źródło
Istnieje ryzyko, że pytanie to zostanie „oparte w głównej mierze na opinii”. Próbowałem podać kilka obiektywnych poglądów w mojej odpowiedzi poniżej.
Colin 't Hart
2
Ten problem jest całkiem realny, a każdy typ danych ma zupełnie inne znaczenie. Z pewnością nie uznałbym tego pytania za oparte głównie na opiniach.
Basil Bourque,

Odpowiedzi:

29

Zasada ta jest zawarta w wielu miejscach, ale myślę, że warto wspomnieć, zawsze gdy porównamy timestamp with time zonez timestamp without time zonerodzajów: nie przechowuje strefy czasowej informacji wraz ze znacznikiem czasu . To, co robi, to przechowywanie wszystkich danych w strefie czasowej UTC, jak stwierdzono w dokumentach :timestamp WITH time zone

W przypadku znacznika czasu ze strefą czasową wewnętrznie przechowywana wartość jest zawsze wyrażona w UTC (Universal Coordinated Time, tradycyjnie znany jako Greenwich Mean Time, GMT). Wartość wejściowa z określoną jawną strefą czasową jest konwertowana na UTC przy użyciu odpowiedniego przesunięcia dla tej strefy czasowej. Jeśli w ciągu wejściowym nie podano żadnej strefy czasowej, zakłada się, że znajduje się ona w strefie czasowej wskazanej przez parametr TimeZone systemu i jest konwertowana na UTC przy użyciu przesunięcia strefy czasowej.

Uważa się, że niektóre z nich mogą być używane timestamp WITHOUT time zonew sytuacjach, w których (1) wszystko znajduje się w tej samej strefie czasowej lub (2) warstwa aplikacji obsługuje strefę czasową i po prostu przechowuje wszystko w określonej strefie czasowej (zwykle UTC). Ale jest również uważany za anty-wzorzec, prosty, ponieważ poprawnym rozwiązaniem dla (1) jest skonfigurowanie ustawienia strefy czasowej na podaną jedną strefę czasową dla systemu, a (2) jest już rozwiązane, ponieważ PostgreSQL przechowuje już wszystko w tej samej strefie czasowej (UTC).

Teraz, gdy te dwa są na dole, mogę przyjść tylko z jednego dobrego powodu, aby użyć timestamp WITHOUT time zone. Właśnie wtedy chcesz przechowywać zdarzenia w przyszłości, a kiedy dotrzemy do tego czasu, musi zostać uruchomiony jakiś alarm. Może to być dobre, timestamp WITH time zonejeśli i tylko wtedy, gdy reguły określone przez regionalne przepisy dotyczące strefy czasowej nigdy się nie zmienią. Najczęstszą regułą, która się zmienia, jest przyjęcie lub brak czasu letniego (DST).

Na przykład wyobraź sobie, że planujesz, powiedzmy, 2013-06-15(jeszcze nie w czasie letnim) zaplanować jakieś wydarzenie w 2013-01-15 10:00(które byłoby już w czasie letnim), a 2013-06-15twój region został wyznaczony do przyjęcia czasu letniego; ale jakiś czas później rząd zmienił regułę i powiedział, że twój region nie będzie już używać DST, i nagle twój planowany czas staje się 2013-01-15 11:00(zamiast 10:00), że jeśli użyjesz timestamp WITH time zonei będziesz aktualizować konfiguracje TZ. Oczywiście możesz również zauważyć, że takie przypadki można traktować również w strefie czasowej, jeśli śledzisz zmiany reguł w regionach / strefach czasowych, które Cię interesują, i aktualizujesz dane, których to dotyczy.

Warto wspomnieć, że niektóre regiony często zmieniają te zasady (jak w Brazylii, niektóre stany - nie cały kraj - często się zmieniają), ale w większości przypadków zmienia to bardzo wcześniej, więc na użytkowników będą miały wpływ tylko wydarzenia zaplanowane bardzo daleko od aktualny czas.

Biorąc to wszystko pod uwagę, mam tylko jedną sugestię. Jeśli masz użytkowników, dzienniki lub cokolwiek innego w różnych strefach czasowych, zapisz strefę czasową, z której pochodzą, i wybierz i użyj timestamp with time zone. W ten sposób możesz (1) krzyżować zdarzenia zachodzące bliżej siebie dla różnych źródeł (niezależnie od ich stref czasowych) i (2) pokazywać pierwotny czas (czas zegarowy), w którym zdarzenie miało miejsce.

MatheusOl
źródło
Mówisz: „Mogę przyjechać tylko z jednym dobrym powodem, aby używać znacznika czasu ze strefą czasową”. Jeśli to nie literówka, to czy rzeczywiście sugerujesz, że „znacznik czasu bez strefy czasowej” jest właściwie bardziej odpowiedni / mniej podatny na nieporozumienia niż „znacznik czasu ze strefą czasową”? Wydaje mi się to sprzeczne z intuicją.
Marcus Junius Brutus
@MarcusJuniusBrutus, przepraszam za to, to rzeczywiście literówka i pomyślałem na odwrót ... Sprawdź zredagowaną odpowiedź.
MatheusOl
codeblog.jonskeet.uk/2019/03/27/... szczegółowo omawia ten scenariusz przyszłych zdarzeń, które mogą zmienić reguły (z tym samym wnioskiem)
Beni Cherniavsky-Paskin
17

Tak. Istnieją przypadki użycia dla TIMESTAMP WITHOUT TIME ZONE.

  • W typowych aplikacjach biznesowych tego typu można używać tylko do:
    • Rezerwacja przyszłych spotkań
    • Reprezentujący tę samą porę dnia w różnych strefach czasowych, takich jak południe w 23 dniu w Tokio i Paryżu (dwie różne godziny w odstępie godzin, ta sama pora dnia)
  • Aby śledzić momenty, zawsze używaj określonych punktów na osi czasu TIMESTAMP WITH TIME ZONE, a nie WITHOUT.

TIMESTAMP WITHOUT TIME ZONEwartości nie są punktem na osi czasu, a nie faktycznymi momentami. Przedstawiają przybliżone wyobrażenie o potencjalnych momentach, możliwych punktach na osi czasu w zakresie około 26-27 godzin (zakres stref czasowych na całym świecie). Nie mają one żadnego rzeczywistego znaczenia, dopóki nie zastosujesz strefy czasowej lub nie uwzględnisz UTC .

Np .: Boże Narodzenie

Na przykład powiedz, że musisz zarejestrować początek wakacji / dni świętych.

Table: holiday_

Column: year_         Type: SMALLINT
Column: description_  Type: VARCHAR
Column: start_        Type: TIMESTAMP WITHOUT TIME ZONE

Aby odnotować fakt, że Boże Narodzenie rozpoczyna się po północy 25 grudnia tego roku, musimy powiedzieć 2016-12-25 00:00:00bez żadnej strefy czasowej. Na początku Świętego Mikołaja odwiedza Auckland NZ tuż po północy, ponieważ jest to jedna z najwcześniejszych północy na świecie. Potem idzie w kierunku zachodnim, gdy nadejdzie kolejna północ, wkrótce docierając do Filipin. Następnie renifery idą w kierunku zachodnim, docierając do Indii o północy, co zdarza się kilka godzin po tej północy w Auckland. Znacznie później jest jeszcze północ w Paryżu FR, a jeszcze później północ w Montrealu CA. Wszystkie te wizyty Świętego Mikołaja zdarzają się w różnych momentach , jednak wszystkie odbywają się wkrótce po północy, o północy każdej miejscowości.

Nagrywanie 2016-12-25 00:00:00bez żadnej strefy czasowej jako początku świąt Bożego Narodzenia jest pouczające i zgodne z prawem, ale tylko niejasno. Dopóki nie powiesz „Boże Narodzenie w Auckland” lub „Boże Narodzenie w Montrealu”, nie mamy określonego momentu. Jeśli rejestrujesz faktyczny moment za każdym razem, gdy sanie lądują, użyj TIMESTAMP WITH TIME ZONEraczej niż WITHOUTtypu.

Podobnie jak Boże Narodzenie jest Sylwester. Kiedy piłka Times Square spada w Nowym Jorku , ludzie w Seattle nadal chłodzą szampana i przygotowują imprezowe rogi . Nagrywalibyśmy jednak ideę noworocznego momentu jak 2017-01-01 00:00:00w TIMESTAMP WITHOUT TIME ZONE. W przeciwieństwie do tego, jeśli chcemy nagrywać, kiedy piłka spadła w Nowym Jorku lub gdy mieszkańcy Seattle rozwalili rogi, zamiast tego użylibyśmy TIMESTAMP WITH TIME ZONE(nie WITHOUT) nagrania tych faktycznych chwil, co trzy godziny od siebie.

Np .: Zmiany fabryczne

Innym przykładem może być rejestrowanie polityki, która obejmuje czas naścienny w różnych lokalizacjach. Załóżmy, że mamy fabryki w Detroit, Düsseldorfie i Delhi. Jeśli powiemy, że we wszystkich trzech fabrykach pierwsza zmiana zaczyna się o 6 rano z przerwą na lunch o 11:30, którą można zapisać jako TIMESTAMP WITHOUT TIME ZONE. Ponownie, ta informacja jest użyteczna w sposób niejasny, ale nie wskazuje określonego momentu w czasie, dopóki nie zastosujemy strefy czasowej. Na wschodzie zaczyna się nowy dzień. Tak więc fabryka w Delhi zostanie otwarta jako pierwsza o szóstej rano. Kilka godzin później fabryka w Düsseldorfie rozpoczyna pracę o 6 rano. Ale fabryka w Detroit otworzy się dopiero po sześciu godzinach, kiedy nastąpi 6 rano.

Porównaj ten pomysł (kiedy zazwyczaj zaczyna się zmiana fabryki) z faktem historycznym, kiedy każdy pracownik fabryki zarejestrował się, aby rozpocząć zmianę w danym dniu. Wejście w to prawdziwy moment, rzeczywisty punkt na osi czasu. Nagrywalibyśmy to w kolumnie typu, TIMESTAMP WITH TIME ZONEa nie WITHOUTtypu.

Tak, istnieją uzasadnione przypadki użycia TIMESTAMP WITHOUT TIME ZONE. Ale z mojego doświadczenia z aplikacjami biznesowymi są stosunkowo rzadkie. W biznesie zależy nam na faktycznych momentach: kiedy faktura rzeczywiście dotarła, kiedy dokładnie umowa wchodzi w życie, w którym momencie wykonano tę transakcję bankową. Więc w takich typowych sytuacjach chcemy tego TIMESTAMP WITH TIME ZONEtypu.

Aby uzyskać więcej dyskusji, zobacz moją odpowiedź na podobne pytanie, czy powinienem przechowywać znaczniki czasu UTC lub czas lokalny dla zmian

Postgres

Pamiętaj, że Postgres nigdy nie zapisuje informacji o strefie czasowej określonych podczas wstawiania znacznika czasu.

  • TIMESTAMP WITH TIME ZONE
    • Każda określona strefa czasowa lub przesunięcie zawarte w danych wejściowych służy do dostosowania wartości do UTC i zapisania. Informacje o strefie / przesunięciu są następnie odrzucane. Pomyśl TIMESTAMP WITH TIME ZONEjak TIMESTAMP WITH RESPECT FOR TIME ZONE.
    • Wejście o 12:00 w dniu 7 marca tego roku w Indiach zostanie dostosowana do godziny UTC poprzez odjęcie pięciu i pół godziny: 6:30 rano.
  • TIMESTAMP WITHOUT TIME ZONE
    • Każda określona strefa czasowa lub przesunięcie zawarte w danych wejściowych jest całkowicie ignorowane.
    • Dane wejściowe o godzinie 12:00 w dniu 7 marca tego roku w Indiach są rejestrowane jako 12:00 w dniu 7 marca tego roku bez żadnych korekt.

Standard SQL ledwo dotyka kwestii typów danych i zachowania w czasie. Baza danych różni się więc znacznie pod względem obsługi daty i godziny.

Basil Bourque
źródło
ponadto przy zmianach w fabryce (lub w szpitalu) każdy, kto pracuje na zmianie cmentarza w dniach zmiany czasu letniego, będzie miał niepoprawnie rejestrowane godziny, bez rejestracji w strefie czasowej.
Jasen
Wydaje mi się, że w ostatnim przykładzie jest literówka: „Wejście o godzinie 12:00 w dniu 7 marca… powinno być” zarejestrowane jako 12 : 00 ”(nie 21:00)
TmTron
11

Chciałbym dodać do tego inny widok, który jest sprzeczny z większością tego, co napisano w innych odpowiedziach. Moim zdaniem timestamp with time zonema bardzo mało ważnych przypadków użycia i timestamp without time zoneogólnie powinien być preferowany.

Po pierwsze, musisz zrozumieć wzorzec „UTC wszędzie”, który jest ogólnie zalecany dla wszystkich aplikacji, które nie mają specjalnych wymagań. Oznacza to po prostu, że Twoja aplikacja powinna reprezentować wszystkie swoje znaczniki czasu w UTC, wszędzie i przez cały czas. Oczywiście będziesz pokazywał użytkownikom lokalną datę / godzinę, ale pomysł polega na przekonwertowaniu ich na samym brzegu programu podczas renderowania widoku. To właściwe miejsce, aby połączyć znacznik czasu UTC (który mógł zostać załadowany z bazy danych) i strefę czasową użytkownika (która mogła pochodzić z przeglądarki) w lokalny znacznik czasu.

Jeśli podążasz za tym wzorem, to timestamp with time zonejest to anty-wzór. Wszystko to sprawia, że ​​PostgreSQL wykonuje konwersje strefy czasowej podczas odczytu i zapisu znaczników czasu, w oparciu o TimeZonezmienną sesyjną PostgreSQL . Zamiast zajmować się strefami czasowymi na samym skraju aplikacji, wprowadziłeś je w samo serce, w samą komunikację z bazą danych. Musisz zawsze zadbać o to, aby PostgreSQL był zawsze TimeZoneodpowiednio skonfigurowany, dodając kolejny niepotrzebny punkt awarii i zamieszania.

I po co? Jeśli podążasz za wzorcem UTC wszędzie, twoja aplikacja i tak ma tylko znaczniki czasu UTC; więc po co prosić bazę danych o przeprowadzanie na nich konwersji stref czasowych? Możesz po prostu przechowywać je w timestamp without time zonekolumnie i traktować jak zawsze UTC. Bez konwersji, bez stref czasowych, bez komplikacji.

Shay Rojansky
źródło
2
Myślę, że zwolennicy timestamptz popierają również wzorzec „UTC wszędzie”. Czy to tylko reguła, która jest egzekwowana na poziomie bazy danych, zamiast polegać tylko na programistach aplikacji / API, aby ją wymusić? Jeśli jesteś w stanie egzekwować tę praktykę, dlaczego nie? Możesz także wymusić, aby wszystkie połączenia Postgres ustawiły strefę czasową na UTC. Nawet jeśli nie, format ISO będzie zawierać przesunięcie tz. Czyż nie jest to wszędzie to samo, co UTC, ale egzekwowane?
iamnat
3
Po pierwsze, jeśli twoja strefa czasowa PostgreSQL jest ustawiona na cokolwiek innego niż UTC i używasz timestamptz, twój program odczytuje znaczniki czasu inne niż UTC. To po prostu nie jest wzorzec „UTC wszędzie” i w zależności od języka klienta może, ale nie musi, powodować wielu komplikacji. Albo jesteś wszędzie UTC, albo używasz lokalnych znaczników czasu ....
Shay Rojansky
Po drugie, ponownie, jeśli jesteś w UTC wszędzie w swojej aplikacji, po prostu nie ma przesunięcia tz do wysłania w formacie ISO dla twoich znaczników czasu. Szczegóły będą się różnić w zależności od języka, ale najlepiej używać typu klienta, który nie jest w stanie reprezentować niczego poza znacznikiem czasu UTC (np. InstanceW NodaTime / JodaTime). Zasadniczo
opisujesz
Po raz kolejny bardzo łatwo jest wyobrazić sobie nową instancję PostgreSQL na pewnym serwerze, która przypadkowo zachowuje strefę czasową komputera lokalnego, która jest domyślnie skonfigurowana. Aplikacje odczytują z tego serwera i pobierają lokalne znaczniki czasu w całkowicie dowolnej strefie czasowej (w której znajduje się serwer). Dlaczego mielibyśmy chcieć tej dodatkowej komplikacji?
Shay Rojansky
1
Mógłby, ale w takim przypadku użycie byłoby jeszcze mniej sensowne timestamptz. Celem tego typu jest wykonywanie konwersji stref czasowych jako wartości odczytanych i zapisanych w PostgreSQL (wewnętrznie w bazie danych znacznik czasu jest zawsze zapisywany jako UTC). Zawsze ustawiając strefę czasową sesji na UTC, skutecznie wyłącza te konwersje, więc po timestamptzco w ogóle korzystać? Innymi słowy, jeśli wartości w bazie danych to UTC, a wartości przychodzące i wychodzące z bazy danych są zawsze UTC, to po co w ogóle mieć świadomość strefy czasowej w bazie danych?
Shay Rojansky
2

dateDatownik również nie zawiera informacji czasowej, jednak wiele osób z niego korzystać.

Oczywiście samo to nie jest odpowiedzią.

Można go używać timestampi datedla dowolnych znaczników czasu i dat, które zawsze znajdują się w tej samej strefie czasowej lub są przechowywane względem pewnej znanej strefy czasowej.

Jeśli strefa czasowa jest zawsze taka sama lub niejawna, to raczej antypattern ma ją przechowywać, niż nie przechowywać (informacje redundantne).

Znaczniki czasu mogą być również używane do przechowywania informacji technicznych, takich jak używane w dziennikach aplikacji lub do pomiarów wydajności. W takim przypadku strefa czasowa może być również nieistotna.


I odwrotnie, jeśli projektujesz lub pracujesz w systemie rozproszonym lub w dowolnym systemie, w którym części systemu będą dystrybuowane w różnych strefach czasowych, może to być uważane za anty-wzorzec, którego nie należy używać timestamp with timezone, chociaż niektóre systemy mogą być zaprojektowane do działania w jednej strefie czasowej, np. UTC. W takim przypadku logika strefy czasowej może być wpychana do warstwy aplikacji - ale tak, uważam to za anty-wzór.

Colin 't Hart
źródło
Rozumiem, że w niektórych przypadkach używanie go nie boli timestamp without timezone, ale czy kiedykolwiek coś mi kupuje? W przeciwnym razie dlaczego miałbym się przejmować, jeśli timestamp with timezone datatyp jest zawsze jednakowy lub bardziej odpowiedni?
Marcus Junius Brutus
Moim głównym argumentem byłoby nieprzechowywanie zbędnych informacji. Zakładam, że arytmetyka daty też timestamp without timezonebyłaby szybsza, ale jest to prawdopodobnie ważne tylko wtedy, gdy przetwarzasz miliardy wierszy ...
Colin 't Hart
1
@ Colin'tHart timestampi timestamptzoba są przechowywane w ten sam sposób. Informacje o strefie czasowej nie są przechowywane w timestamptz, ale zamiast tego są konwertowane na UTC w celu przechowywania. Powiedziałbym, zawsze używaj, timestamptzgdy znaczniki czasu oznaczają czas bezwzględny . To wszystko co timestamptzznaczy. Pisałem o tym tutaj .
philipipe
2

Przechowywanie i przetwarzanie dat / godzin w czasie lokalnym może wydawać się kuszące, jeśli twoja aplikacja jest ograniczona do jednej strefy czasowej, ale uważam, że to pomyłka.

Po przełączeniu z czasu letniego na standardowy czas powtarza się godzinę w czasie lokalnym (przy założeniu, że różnica wynosi godzinę). Tam, gdzie mieszkam, dzieje się to zwykle około 2 nad ranem, więc czas lokalny biegnie 01:58, 01:59, 01:00 i przesuwa się do 02:00 pod koniec powtarzanej godziny.

Jeśli spróbujesz uporządkować zdarzenia według czasu lokalnego, oznacza to, że zdarzenia z dwóch oddzielnych godzin zostaną zmieszane razem i nie pojawią się w kolejności, w której faktycznie się wydarzyły.

Dla porównania UTC nie ma tego problemu i porządkuje. Tak więc, nawet jeśli pracujesz tylko z jedną strefą czasową, chcesz, aby DB przechowywał i przetwarzał czasy w UTC i konwertował na / z czasu lokalnego dla wprowadzania / wyświetlania. Takie jest zachowanie TIMESTAMP ZE STREFĄ CZASOWĄ.

Steve Fosdick
źródło