Подтвердить что ты не робот

PostgreSQL - как сделать дату в другом часовом поясе?

Мой сервер находится в центральном времени. Я хотел бы сделать временные метки с использованием восточного времени.

Например, я хотел бы сделать 2012-05-29 15:00:00 как 2012-05-29 16:00:00 EDT.

Как я могу это достичь?

to_char('2012-05-29 15:00:00'::timestamptz at time zone 'EST5EDT', 'YYYY-MM-DD HH24:MI:SS TZ') дает 2012-05-29 16:00:00 (без зоны).

to_char('2012-05-29 15:00:00'::timestamp at time zone 'EST5EDT', 'YYYY-MM-DD HH24:MI:SS TZ') дает 2012-05-29 14:00:00 CDT (неверно).

Это работает, но это так смешно сложно, должен быть более простой способ: replace(replace(to_char(('2012-05-29 15:00:00'::timestamptz at time zone 'EST5EDT')::timestamptz, 'YYYY-MM-DD HH24:MI:SS TZ'), 'CST', 'EST'), 'CDT', 'EDT')

4b9b3361

Ответ 1

Ключ состоит в том, чтобы переключить локальный часовой пояс на желаемый часовой пояс дисплея на время транзакции:

begin;
set local timezone to 'EST5EDT';
select to_char('2012-05-29 15:00:00'::timestamp at time zone 'CDT',
  'YYYY-MM-DD HH24:MI:SS TZ');
end;

Результат:

2012-05-29 16:00:00 EDT

Обратите внимание, что при set [local] timezone требуется использовать полные названия часовых поясов вместо сокращений (например, CST не работает). Найдите правильные варианты в представлении pg_timezone_names.

Чтобы использовать этот метод в контексте, подобном вызову to_char(), я считаю, что эта функция выполняет задание:

CREATE FUNCTION display_in_other_tz(
      in_t timestamptz,
      in_tzname text,
      in_fmt text) RETURNS text
AS $$
DECLARE
 v text;
 save_tz text;
BEGIN
  SHOW timezone into save_tz;
  EXECUTE 'SET local timezone to ' || quote_literal(in_tzname);
  SELECT to_char(in_t, in_fmt) INTO v;
  EXECUTE 'SET local timezone to ' || quote_literal(save_tz);
  RETURN v;
END;
$$ language plpgsql;

Ответ 2

На самом деле PG знает все - to_char (x, 'TZ') отличает CST от CDT правильно, и в часовом поясе EST5EDT также относится к DST.

При работе с меткой времени Postgres знает:

При интерпретации ввода Postgres использует информацию о предоставленном часовом поясе. При рендеринге метки времени Postgres использует текущую настройку timezone, но смещение часового пояса, аббревиатура или имя используются только для вычисления правильного значения на входе. Они не сохранены. невозможно извлечь эту информацию позже. Подробнее в этом ответном ответе:

Ваш "правильный" пример почти правильный. TZ of to_char() возвращает "CDT" для временных меток, которые попадают в летние периоды центрального времени и "CST". Восточное время (EST/EDT) переключает летнее время при том же местном времени - цитирую Wikipedia:

Время настраивается в 2:00 по местному времени.

Два часовых пояса не синхронизированы в течение двух часов в год. Конечно, это никогда не может повлиять на отметку времени 15:00 или 16:00, только вокруг 02:00.

Полностью правильное решение - во многом похожее на то, что @Daniel уже опубликовано, слегка упрощенное:

BEGIN;
SET LOCAL timezone to 'EST5EDT';
SELECT to_char('2012-05-29 15:00 CST6CDT'::timestamptz
             , 'YYYY-MM-DD HH24:MI:SS TZ')
RESET timezone;  -- only if more commands follow in this transactions
END;

Эффекты SET LOCAL сохраняются только до конца текущей транзакции.

Руководство по SET LOCAL.