PostgreSQL-如何呈现不同时区的日期?

PostgreSQL-如何呈现不同时区的日期?,postgresql,datetime,timezone,Postgresql,Datetime,Timezone,我的服务器在中央时间。我想使用东部时间渲染时间戳 例如,我希望将2012-05-29 15:00:00渲染为2012-05-29 16:00:00 EDT 我怎样才能做到呢 to_char('2012-05-29 15:00:00':时区'EST5EDT','YYYY-MM-DD HH24:MI:SS TZ')给出了2012-05-29 16:00:00(无区域) to_char('2012-05-29 15:00:00':时区'EST5EDT'的时间戳,'YYYY-MM-DD HH24:MI:

我的服务器在中央时间。我想使用东部时间渲染时间戳

例如,我希望将
2012-05-29 15:00:00
渲染为
2012-05-29 16:00:00 EDT

我怎样才能做到呢

to_char('2012-05-29 15:00:00':时区'EST5EDT','YYYY-MM-DD HH24:MI:SS TZ')
给出了
2012-05-29 16:00:00
(无区域)

to_char('2012-05-29 15:00:00':时区'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'::时区'EST5EDT'的timestamtz)::timestamtz,'yyyyy-MM-DD HH24:MI:SS TZ'),'CST','EST'),'CDT','EDT')

事实上,PG无所不知——to_char(x,'TZ')将CST与 CDT正确,并且在时区EST5EDT也尊重DST

在处理时间戳时,Postgres知道:

  • GUC的设置
  • 这个
  • 该值与
    时间戳
    时间戳
    自“1970-1-1 0:0 UTC”以来的秒数相同。(确切地说,是UT1。)
  • 有关您所在区域中其他时区的详细信息
在解释输入时,Postgres使用提供的时区信息。 呈现时间戳值时,Postgres使用当前的
时区设置,但时区偏移量、缩写或名称仅用于计算输入的正确值。它们未保存。以后提取该信息是不可能的。详情如下:

您的“正确”示例几乎是正确的
TZ
of
to_char()
返回中央时间和'CST'其他夏时制期间的时间戳的'CDT'。东部时间(
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的效果仅持续到当前事务结束


关键是在交易期间将本地时区切换到所需的显示时区:

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

请注意,使用
set[local]timezone
时,需要使用完整的时区名称,而不是缩写(例如,CST不起作用)。在
pg\u时区\u名称
视图中查找有效选项

要在类似于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;

这不是我想要的。我问的是日期渲染,不是转换。我知道如何转换为
时间戳
,我要寻找的是一种在一般情况下使用不同时区名称呈现
varchar
的方法。@KonradGarus:今天早些时候我没有更多的时间。我想我更清楚地理解了您现在想要的是什么,以及为什么您的解决方案几乎正确,但不完全正确。服务器如何知道您要显示哪个时区缩写?它只知道时区和非时区的信息不是黑魔法。没有技术上的理由不可能(甚至很难)说5/29是东部时间的DST。事实上,PG无所不知——
to_char(x,'TZ')
正确区分CST和CDT,时区EST5EDT的
也尊重DST。我唯一缺少的是使用这些信息进行优雅的渲染。这里的问题在于Postgres开发人员奇怪的选择,即带时区的时间戳在_zone
应该转换时区,但是返回没有时区的
时间戳
@lanzz在转换
时间戳
时间戳
和在时区使用
时,有很多奇怪的地方,但是真的没有内置的方法来呈现不同的时区,比如
fmt_日期(x,'yyyyy-MM-DD hhh24:MI:SS-TZ,'EST5EDT'))
?我在过去的某个时候也考虑过同样的问题,就我记忆所及,找不到合理的解决方案。也许您能做的最好的事情是在应用程序端而不是在数据库中管理时区和格式,尽管这并不是您问题的答案。您的第一个答案是正确的。据我所知,OP希望系统根据时间戳输出“EDT”或“EST”。你以后添加的内容在这方面会失败。好的,我可以看出我误解了问题的这一部分。相应地更改我的答案。+1现在非常干净。您的上一个版本也是一个改进,它重置了当前的
时区。我假设默认的时区是
。我喜欢将时区显示为
。这让我明白shell是多么简洁,例如:
TZ=Australia/Perth date