sql >> Databáze >  >> RDS >> PostgreSQL

PostgreSQL date() s časovým pásmem

V podstatě to, co chcete, je:

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

Řešení mám z tohoto článku níže, které je rovnou ZLATÉ!!! Velmi jasně vysvětluje tento netriviální problém, přečtěte si jej, pokud chcete lépe porozumět správě TZ pstgrsql.

Vyjadřování časových razítek PostgreSQL bez zón v místním čase

Zde je to, co se děje. Nejprve byste měli vědět, že „časové pásmo PST je o 8 hodin pozadu za časovým pásmem UTC, takže například 1. ledna 2014, 16:30 PST (středa, 1. ledna 2014 16:00:30 -0800) je ekvivalentní 2. ledna 2014, 00:30 AM UTC (Čt, 2. ledna 2014 00:00:30 +0000). Kdykoli po 16:00 v PST přeskočí na další den, interpretuje se jako UTC.

Také, jak zmínil Erwin Brandstetter výše, postresql má dva typy datových typů časových razítek, jeden s časovou zónou a druhý bez. Pokud vaše časová razítka obsahují časové pásmo, pak jednoduché:

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

bude pracovat. Pokud je však vaše časové razítko bez časového pásma, provedení výše uvedeného příkazu nebude fungovat a musíte NEJPRVE převést časové razítko bez časového pásma na časové razítko s časovou zónou, konkrétně časovou zónou UTC, a POUZE POTOM jej převést na požadované 'PST' nebo 'US/ Pacific' (které jsou stejné až do některých problémů s letním časem. Myslím, že byste měli být v pohodě s oběma).

Dovolte mi demonstrovat na příkladu, kde vytvořím časové razítko bez časového pásma. Předpokládejme pro pohodlí, že naše místní časové pásmo je skutečně „PST“ (pokud tomu tak nebylo, bude to trochu složitější, což je pro účely tohoto vysvětlení zbytečné).

Řekni, že mám:

$ 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

Výsledkem bude:

"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"

Poslední časové razítko je důvodem všeho zmatku ohledně převodu časového razítka bez časového pásma z UTC na 'PST' v postgresql. Když píšeme:

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

Bereme časové razítko bez časového pásma a snažíme se ho převést na 'PST TZ (nepřímo předpokládáme, že postgresql pochopí, že chceme, aby převedl časové razítko z UTC TZ, ale postresql má své vlastní plány!). V praxi postgresql dělá to, že vezme časové razítko bez časového pásma ('2014-01-2 00:30:00) a zachází s ním, jako by to JIŽ BYLO časové razítko 'PST' TZ (tj.:2014-01-2 00:30 :00 -0800) a převede to na časové pásmo UTC!!! Takže to vlastně posouvá 8 hodin dopředu místo zpátky! Tak dostáváme (2014-01-02 08:30:00+00).

Každopádně toto poslední (neintuitivní) chování je příčinou všeho zmatku. Přečtěte si článek, pokud chcete důkladnější vysvětlení, ve skutečnosti jsem dostal výsledky, které jsou trochu jiné než v této poslední části, ale obecná myšlenka je stejná.



  1. Analytics s MariaDB AX – tThe Open Source Columnar Datastore

  2. 2 způsoby, jak odstranit duplicitní řádky v SQLite

  3. MySQL a PHP:UTF-8 se znaky azbuky

  4. Jak změním SQL Server 2005 tak, aby rozlišoval malá a velká písmena?