30

我的服务器在中部时间。我想使用东部时间呈现时间戳。

例如,我想渲染2012-05-29 15:00:002012-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')

4

2 回答 2

40

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

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_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;
于 2012-05-29T15:21:31.517 回答
4

事实上,PG 知道这一切 - to_char(x, 'TZ') 正确区分 CST 和 CDT,并且在时区 EST5EDT 也尊重 DST。

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

  • GUC 的设置timezone
  • 数据类型
  • ,与 和的'1970-1-1 0:0 UTC' 以来的秒数timestamp相同timestamptz。(或者,准确地说:UT1。)
  • 日期/时间配置文件中有关其他时区的详细信息

在解释输入时,Postgres 使用有关提供的时区的信息。渲染时间戳值时,Postgres 使用当前 timezone设置,但时区偏移量缩写名称仅用于计算输入的正确。他们没有得救以后不可能提取该信息。此相关答案中的更多详细信息:

您的“正确”示例几乎是正确的。TZto_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 的效果只持续到当前事务结束。

关于SET LOCAL.

于 2012-05-29T11:21:13.427 回答