【问题标题】:oracle convert unix epoch time to dateoracle 将 unix 纪元时间转换为日期
【发布时间】:2016-09-15 06:23:16
【问题描述】:

上下文是我们的产品中有一个现有的应用程序,它生成 EPOCH 编号并将其发送到现有的预言机程序,反之亦然。它使用类似这样的方法在该过程中工作

SELECT UTC_TO_DATE (1463533832) FROM DUAL
SELECT date_to_utc(creation_date) FROM mytable

当我尝试这些查询时,它对我也适用于 Oracle 10g 服务器(以及 oracle sql developer 4.x,如果这很重要的话)。

在现有程序中,要求是将值保存为日期本身(时间组件无关紧要),但是在新要求中,我必须将 unix EPOCH 值转换为日期时间(在小时/分钟/秒级别,或更好在 oracle 查询中采用特定格式,例如 dd-MMM-yyyy hh:mm:ss)。奇怪的是,我无法通过 Google 找到有关 UTC_TO_DATE 和 DATE_TO_UTC 函数的任何文档。我已经查看了有关 stackoverflow 的所有不同问题,但其中大多数都是特定于编程语言的,例如 php、java 等。

底线,如何在 Oracle 查询中使用这些函数(或任何其他函数)将 EPOCH 转换为该时间级别?此外,我所指的那些功能可能是自定义的或特定的,因为我没有看到任何文档或对此的参考。

【问题讨论】:

  • 这些不是标准函数,它们是您应用程序的一部分。您需要找到它们的来源(在源代码管理中;或者在 user_source 或 all_source 中,如果不存在)。但是你想修改它们,有包含时间的新版本,还是有独立的转换?您还需要检查您传入 /get back 的日期是否也是 UTC 或代表不同的地区 - 您的函数可能正在调整它们。
  • @AlexPoole 感谢您的建议。我确实觉得它们可以是自定义的,但我必须承认,我没有意识到它们可以在我的代码库本身中自定义。所以是的,我在源代码管理中找到了它们的定义,它们的内部工作与 tbone 在下面分享的几乎相同..
  • 他们是否将日期更改为不同的时区,或者他们是否假设日期也代表 UTC?鉴于您对 tbone 的回答的评论,您确定他们还没有设置时间组件,而您只是没有看到那些?
  • @AlexPoole 这就是他们所拥有的 - RETURN to_date('01.01.70','dd.mm.rr') + (utc_in/(60*60*24));所以我认为他们实际上并没有更改为当地时间,他们也想将其存储为 UTC.. 我也是.. 是的,一旦我更改了客户端的格式,我可以看到他们自定义的时间功能也很好

标签: oracle datetime unix date-format epoch


【解决方案1】:

从纪元的毫秒数转换(假设纪元是 1970 年 1 月 1 日):

select to_date('19700101', 'YYYYMMDD') + ( 1 / 24 / 60 / 60 / 1000) * 1322629200000
from dual;

2011 年 11 月 30 日上午 5:00:00

将该日期转换回毫秒:

select (to_date('11/30/2011 05:00:00', 'MM/DD/YYYY HH24:MI:SS') - to_date('19700101', 'YYYYMMDD')) * 24 * 60 * 60 * 1000
from dual;

1322629200000

如果它是秒而不是毫秒,则省略等式的 1000 部分:

select to_date('19700101', 'YYYYMMDD') + ( 1 / 24 / 60 / 60 ) * 1322629200
from dual;

select (to_date('11/30/2011 05:00:00', 'MM/DD/YYYY HH24:MI:SS') - to_date('19700101', 'YYYYMMDD')) * 24 * 60 * 60
from dual;

希望对您有所帮助。

【讨论】:

  • 注意,只有当您的本地时区也是 UTC 时,才会给出正确的结果。
  • 谢谢@tbone,这很接近了。我唯一的评论是,如果我做你的查询,甚至这个 - 选择 to_date('19700101', 'YYYYMMDD HH24:MI:SS ') + ( 1 / 24 / 60 / 60 ) * 1463533832 来自双重;仍然在 Sql Developer 输出窗口中,我看到了这个 - TO_DATE('19700101','YYYYMMDDH ----------------------------- 18- 5 月 16 日 有什么想法为什么我看不到小时、分钟和秒
  • @SubhashDike - 这就是您的客户显示日期的方式;更改您的 NLS_DATE_FORMAT 或(最好)使用 to_char() 指定格式,使用类似“YYYY-MM-DD HH24:MI:SS”的掩码。
  • @AlexPoole 很棒的建议.. 我调整了我的 sql 开发人员设置,这就是我现在看到的,完美! - TO_DATE('19700101','YYYYMMDDH ----------------------------- 18-MAY-16 01:10:32跨度>
  • select to_date('19700101', 'YYYYMMDD') + ( 1 / 24 / 60 / 60 / 1000) * 1322629200000 from dual; 这不会格式化为时分秒
【解决方案2】:

另一种选择是使用区间类型:

SELECT TO_TIMESTAMP('1970-01-01 00:00:00.0'
                   ,'YYYY-MM-DD HH24:MI:SS.FF'
       ) + NUMTODSINTERVAL(1493963084212/1000, 'SECOND')
FROM dual;

它的优点是毫秒不会被削减。

【讨论】:

  • 一个纪元通常在 UTC 时区。除了TO_TIMESTAMP,您可以使用TO_TIMESTAMP_TZ 并将UTC 添加到字符串中,或​​者更简单地使用时间戳文字TIMESTAMP '1970-01-01 00:00:00 UTC'
【解决方案3】:

这里适用于 UTC/GMT 和 EST;

GMT  select (to_date('1970-01-01 00','yyyy-mm-dd hh24') +
     (1519232926891)/1000/60/60/24) from dual;

EST  select new_time(to_date('1970-01-01 00','yyyy-mm-dd hh24') + 
     (1519232926891)/1000/60/60/24, 'GMT', 'EST') from dual;

【讨论】:

    【解决方案4】:

    如果您的纪元时间存储为整数...... 并且您希望转换为 Oracle 日期格式。

    步骤 1--> 将您的纪元日期 (1462086000) 添加到标准 01-jan-1970。 86400 是 24 小时内的秒数。

    *Select TO_DATE('01-jan-1970',   'dd-mon-yyyy') + 1462086000/86400 from dual*  
       **output is 5/1/2016 7:00:00 AM**
    

    第 2 步--> 将其转换为 CHAR 。这是在应用其他功能之前进行格式化所必需的。

      *Select TO_CHAR(TO_DATE('01-jan-1970',   'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss') from dual*
    
       output is  2016-05-01 07:00:00
    

    第 3 步--> 现在进行时间戳转换

    Select to_timestamp(TO_CHAR(TO_DATE('01-jan-1970',   'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss') from dual
    
      output is 5/1/2016 7:00:00.000000000 AM
    

    第 4 步--> 现在需要时区,使用 UTC

    Select from_tz(to_timestamp(TO_CHAR(TO_DATE('01-jan-1970',   'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'),'UTC')  from dual
    
         output is 5/1/2016 7:00:00.000000000 AM +00:00
    

    第 5 步--> 如果您的时区需要是 PST

     Select from_tz(to_timestamp(TO_CHAR(TO_DATE('01-jan-1970',   'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'),'UTC')  at time zone 'America/Los_Angeles' TZ from dual
    
               output is 5/1/2016 12:00:00.000000000 AM -07:00
    

    步骤 6--> 格式化 PST 时区时间戳。

     Select to_Char(from_tz(to_timestamp(TO_CHAR(TO_DATE('01-jan-1970',   'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'),'UTC')  at time zone 'America/Los_Angeles' ,'DD-MON-YYYY HH24:MI:SS') TZ from dual 
    
              output is  01-MAY-2016 00:00:00
    

    第 7 步--> 最后,如果您的列是日期数据类型

       Add to_DATE to the whole above Select. 
    

    【讨论】:

    • 将字符串转换为 DATE 然后转换为 CHAR 再转换回 TIMESTAMP 似乎毫无意义。
    【解决方案5】:

    我认为有人会对看到这个的 Oracle 函数版本感兴趣:

    CREATE OR REPLACE FUNCTION unix_to_date(unix_sec NUMBER)
    RETURN date
    IS
    ret_date DATE;
    BEGIN
        ret_date:=TO_DATE('19700101','YYYYMMDD')+( 1/ 24/ 60/ 60)*unix_sec;
        RETURN ret_date;
    END;
    /
    

    我有一堆需要日期的记录,所以我更新了我的表格:

    update bobfirst set entered=unix_to_date(1500000000+a);
    

    其中 a 是 1 到 10,000,000 之间的数字。

    【讨论】:

      【解决方案6】:

      一种将时间戳转换为纳秒的更短方法。

      SELECT (EXTRACT(DAY FROM (
          SYSTIMESTAMP --Replace line with desired timestamp --Maximum value: TIMESTAMP '3871-04-29 10:39:59.999999999 UTC'
      - TIMESTAMP '1970-01-01 00:00:00 UTC') * 24 * 60) * 60 + EXTRACT(SECOND FROM
          SYSTIMESTAMP --Replace line with desired timestamp
      )) *  1000000000 AS NANOS FROM DUAL;
      
      NANOS
      1598434427263027000
      

      一种将纳秒转换为时间戳的方法。

      SELECT TIMESTAMP '1970-01-01 00:00:00 UTC' + numtodsinterval(
          1598434427263027000 --Replace line with desired nanoseconds
      / 1000000000, 'SECOND') AS TIMESTAMP FROM dual;
      
      TIMESTAMP
      26/08/20 09:33:47,263027000 UTC
      

      正如所料,上述方法的结果不受时区影响。

      一种将时间间隔转换为纳秒的更短方法。

      SELECT (EXTRACT(DAY FROM (
          INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval --Maximum value: INTERVAL '+694444 10:39:59.999999999' DAY(6) TO SECOND(9) or up to 3871 year
      ) * 24 * 60) * 60 + EXTRACT(SECOND FROM (
          INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval
      ))) * 1000000000 AS NANOS FROM DUAL;
      
      NANOS
      1598434427263027000
      

      一种将纳秒转换为间隔的方法。

      SELECT numtodsinterval(
          1598434427263027000 --Replace line with desired nanoseconds
      / 1000000000, 'SECOND') AS INTERVAL FROM dual;
      
      INTERVAL
      +18500 09:33:47.263027
      

      正如预期的那样,毫秒、微米和纳米被转换和恢复,尽管 SYSTIMESTAMP 没有纳秒信息。

      将 1000000000 替换为 1000,例如,如果您想使用毫秒而不是纳秒。

      我尝试了一些发布的方法,但几乎它们都受到时区的影响或恢复后数据丢失的结果,所以我决定发布适合我的方法。

      【讨论】:

      • 如果您认为此答案回答了您刚刚发布的其他 10 个问题,那么正确的操作不是发布 11 个答案,而是发布一个答案并将其他 10 个问题标记为重复这个。
      猜你喜欢
      • 2013-04-02
      • 2013-01-08
      • 2018-12-27
      • 2018-08-03
      • 2018-10-01
      • 2014-01-25
      • 1970-01-01
      • 2018-04-24
      相关资源
      最近更新 更多