【问题标题】:Timestamp manipulations in PostgreSQL - problem with hours/time zonePostgreSQL 中的时间戳操作 - 小时/时区问题
【发布时间】:2010-12-11 17:50:03
【问题描述】:

我需要在我的数据库上执行一些日期时间操作,这要求所有 created 时间戳具有相同的年份。我试过这个查询:

select created,cast (created - 
    to_timestamp(''||date_part('year', created), 'YYYY') + 
    timestamp '2010-01-01' as timestamp without time zone) 
    from table where created is not null limit 10;

...但结果只是部分令人满意:

       created       |      timestamp      
---------------------+---------------------
 2010-08-29 12:44:05 | 2010-08-29 11:44:05
 2007-06-21 13:49:22 | 2010-06-21 12:49:22
 2007-06-21 15:02:33 | 2010-06-21 14:02:33
 2007-06-21 15:05:26 | 2010-06-21 14:05:26
 1999-09-30 13:00:00 | 2010-09-30 12:00:00
 1997-06-07 13:00:00 | 2010-06-07 12:00:00
 2010-06-15 20:51:01 | 2010-06-15 19:51:01
 2006-08-26 15:33:02 | 2010-08-26 14:33:02
 2009-12-15 11:07:06 | 2010-12-15 11:07:06
 1997-06-28 13:00:00 | 2010-06-28 12:00:00
(10 rows)

如您所见,与原始 created 值相比,所有时间戳都是 -1 小时。更奇怪的是,最后一个(2010-12-15 11:07:06)不是。

created 列是timestamp without time zone 类型。

知道我做错了什么吗?

【问题讨论】:

    标签: sql postgresql timestamp


    【解决方案1】:

    您的 SQL 的问题在于它不会将日期转换为另一年的日期。它计算 created 和 2010-01-01 的增量并将其转换为日期。所以你实际上并没有删除年份部分,而是计算它是多久以前的。

    这是解决问题的另一种方法。它只会替换年份,其余日期保持不变。

    SELECT TO_TIMESTAMP('2010-' || CAST(EXTRACT(MONTH FROM created) AS VARCHAR) || '-' || CAST(EXTRACT(DAY FROM created) AS VARCHAR) || ' ' || CAST(EXTRACT(HOUR FROM created) AS VARCHAR) ||':'||CAST(EXTRACT(MINUTE FROM created) AS VARCHAR) ||':'|| CAST(EXTRACT(SECONDS FROM created) AS VARCHAR), 'YYYY-MM-dd HH24:MI:SS') AS timestamp FROM table;
    

    您也可以使用子字符串来做到这一点。 TO_TIMESTAMP() 会将 2010-02-29 转换为 2010-03-01,因此可以安全使用。

    【讨论】:

      【解决方案2】:

      这是jmz提到的子串解决方案:

      选择 to_timestamp('2010'||substring(to_char(created, 'yyyy-mm-dd hh24:mi:ss.ms'), 5), 'yyyy-mm-dd hh24:mi:ss.ms')

      【讨论】:

        【解决方案3】:

        谢谢大家,jmz 和 a_horse_with_no_name 解决方案都可以正常工作。

        我还修复了我的解决方案。问题出在 to_timestamp 上,它返回 timestamp with time zone,而我预计是 timestamp without time zone。添加一个类型转换就足够了:

        select created,cast (created-to_timestamp(''||
            date_part('year', created), 'YYYY')::timestamp without time zone + 
            timestamp '2010-01-01' as timestamp without time zone) 
            from table;
        

        【讨论】:

          猜你喜欢
          • 2011-03-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-14
          • 2014-10-15
          • 1970-01-01
          相关资源
          最近更新 更多