2013-11-28 12 views
13

Dla ISO8601 datetime zgodnejZachowaj czasowej w PostgreSQL timestamptz typu

2004-10-19 10:23:54+02 

Czy to możliwe, aby mieć tę wartość, z +02 offset, odzwierciedlone w zapamiętanej wartości kolumny, a także zachowane, gdy jest wybrany?

Z mojego czytania appropriate section of the docs Domyślnym zachowaniem PostgreS jest przekształcenie na UTC, w którym to momencie utracono pierwotne przesunięcie. Z pewnością to widzę.

Dostęp do danych odbywa się przez ORM, która nie jest w stanie dodać żadnej specjalnej konwersji tz, więc naprawdę muszę po prostu przechowywać datetime z oryginalnym przesunięciem i mieć wartość odzwierciedloną po wybraniu.

Dla każdego, kto umiera, by powiedzieć mi, że to ta sama instancja w czasie, zachowanie tej wartości ma znaczenie dla tych danych.

+0

Czy możliwe jest zapisanie przesunięcia w oddzielnej kolumnie, dzięki czemu nie jesteś na łasce PostgreSQL? – tadman

+1

@tadman Ha. Próbujesz przetasować to w jedną kolumnę. Nie wydaje się być nierozsądną rzeczą do zrobienia. – markdsievers

+0

Co to jest źródło danych? Ciąg literału? Lub inna kolumna - jakiego typu? –

Odpowiedz

13

Jak już zorientowali się, strefa czasowa nie jest zapisany w ogóle z Postgres data/czas typów, nawet z timestamptz. Jego rolą jest odpowiednio modyfikator wejściowy lub dekorator wyjściowy. Zapisywana jest tylko wartość (punkt w czasie). Obszerne dane w tym powiązanej odpowiedź:

Dlatego, jeśli chcemy zachować tę część ciągu wejściowego, trzeba wyodrębnić go z łańcucha i zapisać go samodzielnie. Chciałbym użyć tabeli jak:

CREATE TABLE tstz 
... 
, ts timestamp -- without time zone 
, tz text 
) 

tz będąc text może posiadać numeryczny przesunięcie jak również strefy czasowej skrót, lub Strefa czasowa nazwy.

Trudność polega na wyodrębnieniu części strefy czasowej zgodnie ze wszystkimi regułami stosowanymi przez parser iw sposób, który nie będzie się łatwo łamał. Zamiast gotować własną procedurę, powoduje, że analizator składni wykonuje pracę.Rozważmy to demo:

WITH ts_literals (tstz) AS (
    VALUES ('2013-11-28 23:09:11.761166+03'::text) 
     ,('2013-11-28 23:09:11.761166 CET') 
     ,('2013-11-28 23:09:11.761166 America/New_York') 
    ) 
SELECT tstz 
     ,tstz::timestamp AS ts 
     ,right(tstz, -1 * length(tstz::timestamp::text)) AS tz 
FROM ts_literals;

SQL Fiddle.

Działa z lub bez T pomiędzy datą i godziną. Kluczem jest tu logika:

right(tstz, -1 * length(tstz::timestamp::text)) AS tz 

Weź to, co pozostało z ciągiem datownika po przycięciu na długość co parser zidentyfikowany jako składnik daty/czasu. Ten opiera się na wejście jest, jak stwierdził:

zatwierdzone ISO8601 ciągi

+2

Dzięki za szczegółową odpowiedź. Rozczarowanie to nie jest możliwe w jednej kolumnie. – markdsievers

+3

@markdsievers Jeśli myślisz o tym, przesunięcie jest zbędne informacje. "Rzeczywistym" czasem jest UTC/GMT, liczba milisekund od epoki. Jeśli w kontekście Twojej aplikacji i danych naprawdę zależy Ci na zachowaniu offsetu, oznacza to, że zależy ci na czasie lokalnym, a to oznacza, że ​​powinieneś przechwytywać i rejestrować strefę czasową. Np .: "Pacyfik/Auckland". Strefa czasowa to więcej niż przesunięcie, zawiera reguły/historię dla czasu letniego (DST) i innych anomalii. Bez rejestrowania strefy czasowej nie ma użytecznego rozróżnienia między datą-czasem + przesunięciem a datą-czasem w UTC. –

1

Natywny postgres date/time datatypes nie zachowuje dla ciebie strefy czasowej wejścia. Jeśli chcesz zarówno zapytać o to jako sygnaturę czasową w bazie danych, jak i przedstawić oryginalne informacje, będziesz musiał w pewien sposób przechowywać obie części informacji.

Zamierzałem zasugerować, że ORM może zdefiniować niestandardowe metody pompowania/deflacji w celu obsługi magii, ale najwyraźniej nie może. Powinieneś wskazać, którego ORM używasz.

Możesz mieć skład ORM/pobrać ciąg w bazie danych i użyć trigger w Postgresie, aby przekonwertować to do timestamptz przechowywanego w innej kolumnie, która jest używana podczas wykonywania zapytań po stronie bazy danych. Jeśli masz wiele tabel z danymi tego typu, może to być trochę nieporęczne.

Jeśli naprawdę chcesz danych w jednej kolumnie w bazie danych, możesz zdefiniować composite type w Postgresie, ale twoja ORM może nie być w stanie sobie z nimi poradzić.

+0

Celowo pominięto szczegóły ORM ponieważ jest to przedmiotem kolejnego pytania. To pytanie dotyczy tylko możliwości zapisania TZ w jednej kolumnie typu PostgreS timestamptz, jak sugeruje tytuł. – markdsievers

2

programistów Java mogą korzystać Joda Time połączeniu z Jadira UserType „s PersistentDateTimeAndZone. Przykład:

@Basic(optional = false) 
@Columns(columns = { @Column(name = "modificationtime"), 
     @Column(name = "modificationtime_zone") }) 
@Type(type = "org.jadira.usertype.dateandtime.joda.PersistentDateTimeAndZone") 
@Index(name = "payment_modificationtime_idx") 
private DateTime modificationTime = null; 

W tym przykładzie wykonania, informacja DateTime w 2 kolumny:

  1. modificationtime timestamp without time zone do przechowywania znacznik czasu w strefie czasu UTC
  2. modificationtime_zone varchar(255) przechowywania strefy czasowej ID jako łańcucha (np America/Caracas)

Podczas gdy Joda Time i Jadira (i Hibernate) są specyficzne dla Java (i jest to de facto), powyższe podejście do konstruowania kolumn RDBMS do przechowywania zarówno znacznika czasowego, jak i strefy czasowej można zastosować do dowolnego języka programowania.

Powiązane problemy