【问题标题】:Get TZ abbrev for given timestamp and TZ name获取给定时间戳和 TZ 名称的 TZ 缩写
【发布时间】:2017-01-21 04:27:48
【问题描述】:

转换timestamptz类型的列后是否可以得到正确的TZ缩写?

例如,我所追求的是显示 “2016-06-16 16:00:00-04”在“美国/太平洋”时区目标 TZ 缩写。 我可以很容易地得到这个:

06/16/2016 01:00 pm

但我无法关注:

06/16/2016 01:00 pm PDT

转换后,timestamptz 变为 timestamp without timezone 并且 to_char 说明符 'TZ' 变得毫无意义...

这是我尝试过的一个例子:

SELECT
    scheduled_dt                                                                           AS scheduled_dt
  , to_char(scheduled_dt, 'TZ')                                                            AS scheduled_dt_orig_tz  
  -- correct value, but missing TZ  
  , timezone('US/Pacific', scheduled_dt)                                                   AS schedules_dt_converted_tz
  , to_char(timezone('US/Pacific', scheduled_dt), 'MM/DD/YYYY HH:MI pm')                   AS scheduled_dt_converted_tz_localized
   -- after conversion TZ is lost
  , to_char(timezone('US/Pacific', scheduled_dt), 'MM/DD/YYYY HH:MI pm TZ')                AS scheduled_dt_converted_tz_localized_missing_tz
  -- with cast, wrong TZ is displayed 
  , to_char(timezone('US/Pacific', scheduled_dt)::timestamptz, 'MM/DD/YYYY HH:MI pm TZ')   AS scheduled_dt_converted_tz_localized_wrong_tz
FROM orders
LIMIT 5  

和样本输出:

"scheduled_dt","scheduled_dt_orig_tz","schedules_dt_converted_tz","scheduled_dt_converted_tz_localized","scheduled_dt_converted_tz_localized_missing_tz","scheduled_dt_converted_tz_localized_wrong_tz"
"2016-06-16 16:00:00-04","EDT","2016-06-16 13:00:00","06/16/2016 01:00 pm","06/16/2016 01:00 pm ","06/16/2016 01:00 pm EDT"
"2014-07-15 08:00:00-04","EDT","2014-07-15 05:00:00","07/15/2014 05:00 am","07/15/2014 05:00 am ","07/15/2014 05:00 am EDT"
"2012-11-27 10:15:00-05","EST","2012-11-27 07:15:00","11/27/2012 07:15 am","11/27/2012 07:15 am ","11/27/2012 07:15 am EST"
"2011-03-02 08:30:00-05","EST","2011-03-02 05:30:00","03/02/2011 05:30 am","03/02/2011 05:30 am ","03/02/2011 05:30 am EST"
"2016-02-12 14:23:09-05","EST","2016-02-12 11:23:09","02/12/2016 11:23 am","02/12/2016 11:23 am ","02/12/2016 11:23 am EST"

【问题讨论】:

    标签: sql postgresql datetime timezone


    【解决方案1】:

    不,因为timestamptz(又名timestamp with time zoneisn't really a timestamp with a time zone,就存储的内容而言...您提供时间戳和时区,在内部它只是存储为UTC 值。

    听起来基本上您应该将目标时区与时间戳一起存储在一个单独的字段中。

    【讨论】:

    • 我用全名存储目标TZ,存储在连接表(warehouse_locations)中,所以我可以隐藏每一行。我缺少的是“moment.js TZ 库之类的功能”,它可以在考虑 DST 的情况下使用短 TZ 名称格式化时间戳......所以我可以根据特定日期和时区获得“PDT”或“PST”。 ...我已经在代码中执行此操作,但想知道是否可以直接在 PG 中执行此操作
    • @zam6ak:我个人会尽量避免在数据库中这样做。我会将其传输到与数据库通信的任何代码作为时间戳和单独的时区,并在那里进行字符串格式化。使用丰富的文化信息等进行格式化时,您往往处于更好的位置。
    • 我完全同意。但是,在我的案例中,数据量很大(500K 和更多行)。因此,为了提高速度,我试图避免“翻译”步骤(本质上是代码中的一个循环,每个时间戳列都被转换)......
    • @zam6ak:好吧,您只会将其传输到数据库中...我不认为在进行转换时它会比您的客户端代码快得多(假设您使用的是合理的客户端平台)——我预计数据传输成本无论如何都会超过转换时间。
    【解决方案2】:

    您无法从timestamptimestamptz 中提取时区(名称或缩写),因为它根本不存在。详细解释:

    由于您使用全名存储目标 TZ,您可能从系统视图 pg_timezone_names(基于内部函数 pg_timezone_names())中提取关联的时区缩写。

    SELECT abbrev
    FROM   pg_timezone_names
    WHERE  name = 'US/Pacific';
    
    abbrev
    --------
    PDT
    

    然而per documentation:

    显示的信息是根据CURRENT_TIMESTAMP的当前值计算出来的。

    这意味着,根据当前时间,您在夏季获得 PDT,在冬季获得 PST不是 基于您要显示的时间戳。

    不是您需要的解决方案,抱歉。

    function definition of pg_timezone_names in the PostgreSQL source code 可能会告诉您如何实现自己的 C 函数。

    相关:

    【讨论】:

    • 经过仔细检查,这不是您需要的解决方案,抱歉。您需要一个函数来获取时区名称和时间戳来生成匹配的时区缩写...
    • 正确。我必须在代码中这样做......你和乔恩的答案都是正确的,并且充满了额外的非常有用的信息。由于乔恩首先回答,我希望你不介意我将他的回复标记为答案。
    • @zam6ak:当然,接受哪个答案完全取决于您。
    猜你喜欢
    • 2020-02-21
    • 2011-12-01
    • 2014-10-10
    • 1970-01-01
    • 2016-02-26
    • 2014-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多