PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

PostgreSQL грешно преобразуване от времеви печат без часова зона към времеви печат с часова зона

Основни неща за разбиране

timestamp without time zone AT TIME ZONE претълкува timestamp като се намира в тази часова зона с цел конвертирането й в UTC .

timestamp with time zone AT TIME ZONE преобразува a timestamptz в timestamp в посочената часова зона.

PostgreSQL използва ISO-8601 часови зони, които уточняват, че източно от Гринуич е положително ... освен ако не използвате спецификатор на часова зона POSIX, в който случай той следва POSIX. Настъпва лудост.

Защо първият дава неочакван резултат

Времевите марки и часовите зони в SQL са ужасни. Това:

select '2011-12-30 00:30:00'::timestamp without time zone AT TIME ZONE 'EST5EDT';

интерпретира въведения с непознат литерал '2011-12-30 00:30:00' като timestamp without time zone , което Pg предполага, че е в местната часова зона, освен ако не е казано друго. Когато използвате AT TIME ZONE , той е (съгласно спецификацията) преинтерпретиран като timestamp with time zone във часовата зона EST5EDT след това се съхранява като абсолютно време в UTC - така че се преобразува от EST5EDT до UTC, т.е. изместването на часовата зона се изважда . x - (-5) е x + 5 .

Това клеймо за време, коригирано към UTC съхранение, след това се коригира за вашия сървър TimeZone настройка за показване, така че да се показва в местно време.

Ако вместо това искате да кажете „Имам тази дата за време в UTC и искате да видя какво е еквивалентното местно време в EST5EDT“, ако искате да сте независими от настройката TimeZone на сървъра, трябва да напишете нещо като:

select TIMESTAMP '2011-12-30 00:30:00' AT TIME ZONE 'UTC'
       AT TIME ZONE 'EST5EDT';

Това гласи:„Дадено времеви отпечатък 2011-12-30 00:30:00, третирайте го като клеймо за време в UTC, когато преобразувате в timestamptz, след което преобразувайте този timestamptz в местно време в EST5EDT.

Ужасно, нали? Искам да дам фирмен разговор с който реши лудата семантика на AT TIME ZONE - наистина трябва да е нещо като timestamp CONVERT FROM TIME ZONE '-5' и timestamptz CONVERT TO TIME ZONE '+5' . Също така timestamp with time zone всъщност трябва да носи часовата си зона със себе си, а не да се съхранява в UTC и автоматично да се преобразува в местно време.

Защо вторият работи (стига TimeZone =UTC)

Вашата оригинална "работна" версия:

select '2011-12-30 00:30:00' AT TIME ZONE 'EST5EDT';

ще бъде правилно само ако TimeZone е настроен на UTC, тъй като преобразуването от текст към timestamptz предполага TimeZone, когато не е посочено.

Защо третото работи

Два проблема се отменят взаимно.

Другата версия, която изглежда работи, е независима от TimeZone, но работи само защото два проблема се самоотменят. Първо, както е обяснено по-горе, timestamp without time zone AT TIME ZONE претълкува клеймото за дата е в тази часова зона за преобразуване в UTC timestamptz; това ефективно изважда изместване на часовата зона.

Въпреки това, по причини, които не са ми познати, PostgreSQL използва времеви печати с обратен знак на това, което съм свикнал да виждам на повечето места. Вижте документацията:

Друг проблем, който трябва да имате предвид, е, че в имената на часовите зони POSIX се използват положителни отмествания за местоположения западно от Гринуич. Навсякъде другаде PostgreSQL следва конвенцията ISO-8601, според която положителните измествания на часовата зона са на изток от Гринуич.

Това означава, че EST5EDT е същото като +5 , а не -5 . Ето защо работи:защото изваждате tz отместването, а не го добавяте, но изваждате отрицателно изместване!

Това, което ви трябва, за да го направите правилно, е:

select TIMESTAMP '2011-12-30 00:30:00' AT TIME ZONE 'UTC'
       AT TIME ZONE '+5';



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Копирайте няколко от колоните на csv файл в таблица

  2. Postgres FOR LOOP

  3. Време за изчакване на заявка в pg-promise

  4. Как да използвам Postgres JSONB тип данни с JPA?

  5. Архивиране на PostgreSQL с помощта на pg_dump и pg_dumpall