Преобразование временных меток Postgres выполняется в обратном направлении

#postgresql #timezone

#postgresql #Часовой пояс

Вопрос:

Сервер находится в EST, я сохраняю timestamptz как lastlogin .

Похоже, что преобразование из UTC в EST происходит в обратном направлении.

 select lastlogin at time zone 'EST' as lastlogin from users where id = 1;
-- > 2021-01-13 18:56:28

select lastlogin at time zone 'UTC' as lastlogin from users where id = 1;
-- > 2021-01-13 13:56:28
 

Если для преобразования из UTC в EST я вычитаю 5 часов, почему EST составляет 5 часов в будущем? Это как если бы преобразование в UTC на самом деле давало мне время EST, а преобразование в EST давало мне время UTC.

Но это работает:

 select NOW() at time zone 'EST', NOW() at time zone 'UTC';
-- > 2021-01-13 14:23:21 2021-01-13 19:23:21
 

Редактировать:

Я обнаружил, что выполнение двух преобразований, похоже, работает:

 select lastlogin at time zone 'UTC' at time zone 'EST' as lastlogin from users where id = 1;
-- > 2021-01-13 13:56:28
 

В Popsql показано, как преобразовать UTC в местный часовой пояс в PostgreSQL. Получается, что первый at time zone устанавливает часовой пояс для времени, в то время как второй фактически выполняет преобразование?

Комментарии:

1. Чему равно значение select lastlogin from users where id = 1; ?

2. Это 2021-01-13 18:56:28

3. Рад, что вы нашли ответ, но хочу предостеречь. Не используйте EST для обозначения часового пояса; это аббревиатура часового пояса. Вместо этого используйте полное название часового пояса; либо US / Eastern, либо America / New York, либо другое со смещением -05:00 — их 34 ***). Это связано с тем, что полное название автоматически настраивается на переход на летнее время, в то время как аббревиатура этого не делает. *** выберите * из pg_timezone_names, где сокращение = ‘EST’;

Ответ №1:

Я понял это.

Во-первых, очевидно, что временная метка может не быть a timestamptz . DBeaver говорит, что это происходит, когда я просматриваю столбцы таблицы, но сообщает timestamp , если я запрашиваю его. Pgcli также говорит , что это a timestamp .

Тем не менее, я обнаружил в документах postgresql 9.9.3 В TIME ZONE, что:

Оператор AT TIME ZONE преобразует временную метку без часового пояса в / из временной метки с часовым поясом и времени со значениями часового пояса в разные часовые пояса.

Объяснение в правке моего вопроса было правильным. AT TIME ZONE on a timestamp установит часовой пояс времени на то, что вы укажете, затем второй AT TIME ZONE преобразует его.

Комментарии:

1. В psql том, что d user показывает lastlogin. Я предполагаю , что так оно и есть timestamptz .

2. Ну, я заметил, что в двух наших базах данных lastlogin отличается, в одном timestamptz и другом timestamp . Вот тут-то я и запутался. Те , что были в этом примере , были timestamp .

3. Смотрите Мой ответ для дальнейшего объяснения. Если вы больше ничего не узнали, почему timestamptz это лучший вариант timestamp .

Ответ №2:

Что вы видите и почему важно хранить значения временных меток в timestamptz :

 set timezone = 'US/Eastern';

test(5432)=> d ts_test 
                         Table "public.ts_test"
  Column  |            Type             | Collation | Nullable | Default 
---------- ----------------------------- ----------- ---------- ---------
 ts_tz    | timestamp with time zone    |           |          | 
 ts       | timestamp without time zone |           |          | 
 ts_txt   | character varying           |           |          | 
 time_fld | time without time zone      |           |          | 

-- A timestamptz field always stores the value as UTC. A timestamp field is stored -- as a naive value. In below the timestamptz value is rotated to EST as that what -- the timezone is set to. The timestamp is also displayed in EST but with no time -- zone value, so naive.

select ts_tz, ts from ts_test ;
             ts_tz              |             ts             
-------------------------------- ----------------------------
 01/14/2021 11:37:13.217229 EST | 01/14/2021 11:37:13.217229

-- Here the time zone is being explicitly set and both values are the same as 
-- timezone = 'EST'. The formally naive value does pick up a time zone designation -- per the docs "timestamp without time zone AT TIME ZONE zone Return Type --timestamp with time -- zone"

select ts_tz AT TIME ZONE 'EST', ts AT TIME ZONE 'EST' from ts_test;
          timezone          |            timezone            
---------------------------- --------------------------------
 01/14/2021 11:37:13.217229 | 01/14/2021 11:37:13.217229 EST

-- Here the the timestamptz value correctly gets rotated to UTC. The timestamp 
-- value gets set to UTC then gets rotated back to EST

 select ts_tz AT TIME ZONE 'UTC', ts AT TIME ZONE 'UTC' from ts_test;
          timezone          |            timezone            
---------------------------- --------------------------------
 01/14/2021 16:37:13.217229 | 01/14/2021 06:37:13.217229 EST