【问题标题】:Convert milliseconds to Timestamp将毫秒转换为时间戳
【发布时间】:2013-03-09 08:28:33
【问题描述】:

我知道要将 Unix 时间戳(以毫秒为单位)转换为我可以使用的 SQL 时间戳

SELECT TO_DATE('1970-01-01','YYYY-MM-DD HH24:MI:SS') + 
       (:timestamp / (1000*60*60*24)) FROM DUAL;

但我需要一个时间戳,所以我尝试了

SELECT TO_TIMESTAMP('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SSFF3') + 
       (:timestamp) from DUAL

这给了我错误:

错误:ORA-01841:(完整)年份必须介于 -4713 和 +9999 之间,并且不能为 0

似乎在时间戳上加 1 总是会将其转换为一天。

我怎样才能获得真正的时间戳?

【问题讨论】:

标签: sql oracle timestamp unix-timestamp milliseconds


【解决方案1】:

如果您将interval 添加到timestamp,您将获得timestamp(请参阅date/interval arithmetics)。

作为Benoit noticed,当它们超过大约 2.1e9 时,您不能指定以秒为单位的间隔:

SQL> SELECT numtodsinterval(2.2e9, 'SECOND'),
  2         numtodsinterval(2.3e9, 'SECOND')
  3    FROM dual;

NUMTODSINTERVAL(2.2E9,'SECOND'  NUMTODSINTERVAL(2.3E9,'SECOND'
------------------------------- -------------------------------
+000024855 03:14:07.147483647   +000024855 03:14:07.147483647

这就是为什么您应该使用不会丢失精度的分钟。例如,假设 :TS 是 unix 时间戳(即数字):

SQL> variable ts number;
SQL> -- determining unix timestamp with nanosecond precision
SQL> BEGIN
  2     :ts := (to_date('2099-01-01 01:02:03', 'yyyy-mm-dd hh24:mi:ss')
  3              - date '1970-01-01') * 1000*60*60*24
  4            + 123.456789;
  5  END;
  6  /

ts
---------
4070912523123,456789

SQL> select timestamp '1970-01-01 00:00:00'
  2         + numtodsinterval((:ts)/1000/60, 'MINUTE')
  3    from dual;

TIMESTAMP'1970-01-0100:00:00'+NUMTODSINTERVAL((:TS)/1000/60,'MINUTE')
---------------------------------------------------------------------------
2099-01-01 01:02:03.123456789

【讨论】:

  • 谢谢。这很好用。特别感谢您提供的链接,这非常有帮助。
  • @radlan 在处理日期 > 2038 时使用 MINUTE,请参阅我的更新;)
【解决方案2】:

有两种类型:

  • 时间戳
  • 间隔

间隔是减去时间戳得到的,把时间戳加在一起是没有意义的。

如果您需要获得毫秒间隔,我建议使用第二个间隔并将其除以 1000:

我可以建议:

SELECT timestamp'1970-01-01 00:00:00' + (interval '1888' second(9) / 1000)
  FROM dual

这里的问题是你不能在同一个时间戳文字中使用超过 9 个数字。

如果您需要将 2,061,464,797,255 毫秒广告到 epoch,我可以建议:

SELECT TIMESTAMP'1970-01-01 00:00:00'
       + INTERVAL '2' SECOND(9) * 1000000000
       + INTERVAL '061464797' SECOND(9)
       + INTERVAL '255' SECOND(3) / 1000
  FROM dual

你得到 2035-04-29 13:06:37.255000000

它似乎受制于 2038 错误:TIMESTAMP'1970-01-01 00:00:00' + 30 亿秒不起作用,而它适用于 20 亿秒。

【讨论】:

  • 函数numtodsinterval没有这样的限制,为什么还要使用这样的静态区间?
  • @Vincent Malgrat:你的方法更好,我的回答只是引入了区间文字。请注意,timestamp'1970-01-01 00:00:00' + numtodsinterval(3000000000,'SECOND') 也有 2038 错误。
  • 不错的收获!我不知道!
  • 也谢谢你。但我喜欢文森特的解决方案。 numtodsinterval 函数非常有用。
【解决方案3】:

我已经发布了here 一些将纳秒转换为时间戳以及将时间戳转换为纳秒的方法。这些方法不受时区影响,精度为纳秒级。

您只需将其调整为使用毫秒而不是纳秒。

SELECT TIMESTAMP '1970-01-01 00:00:00 UTC' + numtodsinterval(
    1598434427263 --Replace line with desired milliseconds
/ 1000, 'SECOND') AS TIMESTAMP FROM dual;

TIMESTAMP
26/08/20 09:33:47,263000000 UTC

【讨论】:

    【解决方案4】:

    使用

    SELECT TIMESTAMP '1970-01-01 00:00:00.1234' + INTERVAL '1 00:00:00' DAY TO SECOND  
           AS ts
      FROM dual;
    

    【讨论】:

    • 这有什么帮助?我需要用它来计算。但是当向它添加数字时,它会被转换为日期(它会丢失时间戳信息)。
    • 请稍等。当您在代码中添加 :timestamp 时,存在一个根本错误。给我一点时间
    猜你喜欢
    • 2016-03-04
    • 2016-03-04
    • 1970-01-01
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多