PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

PostgreSQL date() ze strefą czasową

Zasadniczo to, czego chcesz, to:

$ select starts_at AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific' from schedules where id = 40

Mam rozwiązanie z tego artykułu poniżej, które jest wprost ZŁOTE!!! Wyjaśnia ten nietrywialny problem bardzo jasno. Przeczytaj go, jeśli chcesz lepiej zrozumieć zarządzanie pstgrsql TZ.

Wyrażanie znaczników czasu PostgreSQL bez stref w czasie lokalnym

Oto, co się dzieje. Najpierw powinieneś wiedzieć, że „Strefa czasowa PST jest 8 godzin za strefą czasową UTC, więc na przykład 1 stycznia 2014, 16:30 PST (środa, 1 stycznia 2014 16:00:30 -0800) jest odpowiednikiem 2 stycznia 2014, 00:30 AM UTC (czw, 02 stycznia 2014 00:00:30 +0000). W dowolnym momencie po godzinie 16.00 w czasie PST przechodzi na następny dzień, interpretowany jako UTC.

Ponadto, jak wspomniał powyżej Erwin Brandstetter, postresql ma dwa typy danych znaczników czasu, jeden ze strefą czasową, a drugi bez. Jeśli znaczniki czasu zawierają strefę czasową, to proste:

$ select starts_at AT TIME ZONE 'US/Pacific' from schedules where id = 40

będzie działać. Jeśli jednak Twój znacznik czasu nie zawiera strefy czasowej, wykonanie powyższego polecenia nie zadziała i musisz NAJPIERW przekonwertować swój znacznik czasu bez strefy czasowej na znacznik czasu ze strefą czasową, a mianowicie strefę czasową UTC, i TYLKO WTEDY przekonwertować go na żądany „PST” lub „US/ Pacific” (które są takie same, aż do niektórych problemów z czasem letnim. Myślę, że powinieneś być w porządku z którymkolwiek).

Pozwólcie, że zademonstruję na przykładzie, w którym tworzę znacznik czasu bez strefy czasowej. Załóżmy dla wygody, że nasza lokalna strefa czasowa to rzeczywiście „PST” (jeśli nie była, to robi się trochę bardziej skomplikowana, co jest niepotrzebne do celów tego wyjaśnienia).

Powiedz, że mam:

$ select timestamp '2014-01-2 00:30:00' AS a, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AS b,  timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AT TIME ZONE 'PST' AS c, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d

To da:

"a"=>"2014-01-02 00:30:00"   (This is the timezoneless timestamp)
"b"=>"2014-01-02 00:30:00+00" (This is the UTC TZ timestamp, note that up to a timezone, it is equivalent to the timezoneless one)
"c"=>"2014-01-01 16:30:00" (This is the correct 'PST' TZ conversion of the UTC timezone, if you read the documentation postgresql will not print the actual TZ for this conversion)
"d"=>"2014-01-02 08:30:00+00"

Ostatni znacznik czasu jest przyczyną całego zamieszania związanego z konwersją znacznika czasu bez strefy czasowej z UTC na „PST” w postgresql. Kiedy piszemy:

timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d

Bierzemy znacznik czasu bez strefy czasowej i próbujemy przekonwertować go na „PST TZ (pośrednio zakładamy, że postgresql zrozumie, że chcemy, aby przekonwertował znacznik czasu z UTC TZ, ale postresql ma własne plany!). W praktyce postgresql pobiera znacznik czasu bez strefy czasowej („2014-01-2 00:30:00”) i traktuje go tak, jakby BYŁ JUŻ znacznikiem czasu TZ „PST” (np. 2014-01-2 00:30 :00 -0800) i konwertuje to na strefę czasową UTC!!! Więc faktycznie przesuwa go o 8 godzin do przodu zamiast do tyłu! W ten sposób otrzymujemy (2014-01-02 08:30:00+00).

W każdym razie to ostatnie (nieintuicyjne) zachowanie jest przyczyną wszelkiego zamieszania. Przeczytaj artykuł, jeśli chcesz dokładniejszego wyjaśnienia, faktycznie uzyskałem wyniki, które są nieco inne niż w tej ostatniej części, ale ogólna idea jest taka sama.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak używać EXECUTE FORMAT ... USING w funkcji postgres

  2. Pobierz ostatnią znaną wartość dla każdej kolumny wiersza

  3. Postgres:WSTAW, jeśli jeszcze nie istnieje

  4. Dlaczego pg_restore zwraca pomyślnie, ale w rzeczywistości nie przywraca mojej bazy danych?

  5. Wydajność OLTP od PostgreSQL 8.3