2012-05-29 3 views
23

Мой сервер находится в центральном времени. Я хотел бы сделать временные метки с использованием восточного времени.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')

+0

Как сервер должен знать, какой часовой пояс * сокращение * вы хотите отобразить ? Он знает только часовой пояс * смещение * –

+0

Информация о часовом поясе не является черной магией. Нет никаких технических причин, из-за которых невозможно (или даже трудно) сказать, что 5/29 - это летнее время в Восточном времени. На самом деле PG знает все это - 'to_char (x, 'TZ')' правильно отличает CST от CDT, а 'в часовом поясе EST5EDT' также относится к DST. Единственный бит, которого я пропускаю, - это элегантный рендеринг с использованием этой информации. –

+1

Проблема заключается в странном выборе разработчиков Postgres, что 'timestamp с часовым поясом в _zone_' должен преобразовывать часовые пояса, но возвращать' timestamp без часового пояса'. – lanzz

ответ

30

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

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; 
+0

Ваш * первый * ответ правильный. Насколько я понимаю, OP хочет, чтобы система выдавала «EDT» или «EST» в зависимости от метки времени. В этом отношении ваше последующее дополнение потерпит неудачу. –

+0

Хорошо, я вижу, что я неправильно понял эту часть проблемы. Соответственно меняя свой ответ. –

+1

+1 Очень чисто сейчас. Ваша последняя версия также является улучшением в том, что она сбрасывает текущий 'часовой пояс'. Я принимал по умолчанию 'часовой пояс'. И мне нравится «SHOW timezone INTO». –

3

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

Когда имеешь дело с меткой времени Postgres знает:

  • настройку GUC timezone.
  • data type.
  • Значение , что равное количество секунд с '1970-1-1 0: 0 UTC' для timestamp и timestamptz. (Или, если быть точным:. UT1)
  • Подробная информация о других часовых поясов в вашем date/time configuration files

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

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

Время настраивается в 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 длится только до конца текущей транзакции.

The manual about SET LOCAL.

+0

Это не то, что я искал. Я спросил о дате рендеринга, а не преобразовании. Я знаю, как преобразовать в timestamp, то, что я ищу, - это способ визуализации «varchar» с другим именем часового пояса в общем случае. –

+0

@ KonradGarus: Сегодня у меня не было больше времени раньше. Я думаю, что я более четко понимаю, что вы сейчас, а также почему ваше решение почти, но не совсем корректно. –

Смежные вопросы