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')
Ответы
Ответ 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
.