【问题标题】:Convert timestamp datatype into unix timestamp Oracle将时间戳数据类型转换为 unix 时间戳 Oracle
【发布时间】:2012-08-19 19:10:32
【问题描述】:

我在数据库中有一个时间戳数据类型,格式为 24-JuL-11 10.45.00.000000000 AM,我想将其转换为 unix 时间戳,我该如何获得它?

【问题讨论】:

    标签: oracle oracle10g unix-timestamp


    【解决方案1】:

    这个问题几乎与Convert Unixtime to Datetime SQL (Oracle)相反

    正如贾斯汀凯夫所说:

    没有内置函数。但是写起来比较容易 一。由于 Unix 时间戳是自 1 月 1 日以来的秒数, 1970

    由于从另一个日期中减去一个日期会导致它们之间的天数,因此您可以执行以下操作:

    create or replace function date_to_unix_ts( PDate in date ) return number is
    
       l_unix_ts number;
    
    begin
    
       l_unix_ts := ( PDate - date '1970-01-01' ) * 60 * 60 * 24;
       return l_unix_ts;
    
    end;
    

    自 1970 年以来以 为单位,小数秒数无关紧要。不过,您仍然可以使用时间戳数据类型调用它...

    SQL> select date_to_unix_ts(systimestamp) from dual;
    
    DATE_TO_UNIX_TS(SYSTIMESTAMP)
    -----------------------------
                       1345801660
    

    对于您的评论,我很抱歉,但我没有看到这种行为:

    SQL> with the_dates as (
      2    select to_date('08-mar-12 01:00:00 am', 'dd-mon-yy hh:mi:ss am') as dt
      3      from dual
      4     union all
      5    select to_date('08-mar-12', 'dd-mon-yy')
      6      from dual )
      7  select date_to_unix_ts(dt)
      8    from the_dates
      9         ;
    
    DATE_TO_UNIX_TS(DT)
    -------------------
             1331168400
             1331164800
    
    SQL>
    

    相差 3,600 秒,即 1 小时。

    【讨论】:

    • 我传递给 PDate 的值来自 $sql = Select TO_DATE(TO_CHAR(fld_from_date, 'DD-Mon-YY HH:MI:SS AM'), 'DD-Mon-YY HH: MI:SS AM') AS date_for_unix_timestamp) 假设上述查询中的 TO_CHAR(fld_from_date, 'DD-Mon-YY HH:MI:SS AM') 结果为 '08-Mar-12 01:00:00 AM' ,则 to_date这个字符的 covesrion 只是 '08-Mar-12' ,HH:MI:SS (01:00:00 AM) 没有出现的原因是什么?
    • 嗨@deepti,没有必要发布另一个答案。您可以随时单击问题上的编辑链接并在此处进行更改。评论也会给我留下通知。我已经更新了我的答案;缺乏可见性可能与您的客户有关?
    • 学习时间和闰秒我不得不说你的程序解决方案是正确的,但引用的 Unix Time 定义不是:Unix Time is not the Number of Seconds since 1.1.1970, but it is "自 1970 年 1 月 1 日以来的天数乘以 60 * 60 * 24 加上自今天午夜以来的秒数!
    • 该函数不考虑您当前的时区。 Unix 时间戳是自 1970 年 1 月 1 日 00:00:00 UTC 以来的秒数。仅当您的本地时区为 UTC 时,结果才正确。
    【解决方案2】:

    我意识到答案已被接受,但我认为应该明确该答案中的函数不考虑传入日期的时区偏移量。应在 GMT (+0) 计算正确的 Unix 时间戳。 Oracle 的to_date 函数假定传入的日期在本地时区,除非另有说明。夏令时是真实存在的,这一事实加剧了这个问题。我通过以下功能解决了这个问题:

    create or replace
      function unix_time_from_date
          (
            in_date   in date,
            in_src_tz in varchar2 default 'America/New_York'
          )
        return integer
      as
        ut      integer       := 0;
        tz      varchar2(8)   := '';
        tz_date timestamp with time zone;
        tz_stmt varchar2(255);
      begin
        /**
         * This function is used to convert an Oracle DATE (local timezone) to a Unix timestamp (UTC).
         *
         * @author James Sumners
         * @date 01 February 2012
         *
         * @param in_date An Oracle DATE to convert. It is assumed that this date will be in the local timezone.
         * @param in_src_tz Indicates the time zone of the in_date parameter.
         *
         * @return integer
         */
    
        -- Get the current timezone abbreviation (stupid DST)
        tz_stmt := 'select systimestamp at time zone ''' || in_src_tz || ''' from dual';
        execute immediate tz_stmt into tz_date;
        select
          extract(timezone_abbr from tz_date)
        into tz
        from dual;
    
        -- Get the Unix timestamp
        select
          (new_time(in_date, tz, 'GMT') - to_date('01-JAN-1970', 'DD-MM-YYYY')) * (86400)
        into ut
        from dual;
    
        return ut;
    end unix_time_from_date;
    

    我有一些配套函数,unix_timeunix_time_to_date,可在 http://jrfom.com/2012/02/10/oracle-and-unix-timestamps-revisited/ 获得。如果不实施这些,我无法相信 Oracle 已经一路发展到 11g。

    【讨论】:

    • 动态SQL和SELECT ... INTO FROM dual没有理由。 NEW_TIME 仅支持所有时区的一小部分,因此它可能会失败。如果输入日期不在当前季节也会失败,试试unix_time_from_date(SYSDATE + 150)
    【解决方案3】:

    日期:

       FUNCTION date_to_unix (p_date  date,in_src_tz in varchar2 default 'Europe/Kiev') return number is
    begin
        return  round((cast((FROM_TZ(CAST(p_date as timestamp), in_src_tz) at time zone 'GMT') as date)-TO_DATE('01.01.1970','dd.mm.yyyy'))*(24*60*60));
    end;
    

    时间戳:

    FUNCTION timestamp_to_unix (p_time  timestamp,in_src_tz in varchar2 default 'Europe/Kiev') return number is
        begin
            return  round((cast((FROM_TZ(p_time, in_src_tz) at time zone 'GMT') as date)-TO_DATE('01.01.1970','dd.mm.yyyy'))*(24*60*60));
        end;
    

    【讨论】:

    • 我发现 - 我认为如下所述 - 这个功能在夏季不能正常工作。 IE。它没有考虑实际偏移量,即。夏令时 (!) 在确切的 p_time 但只有查询运行时的偏移量
    【解决方案4】:

    我正在使用以下方法,它与其他答案略有不同,因为它使用sessiontimezone() 函数来正确获取日期

        select
        ( 
          cast((FROM_TZ(CAST(in_date as timestamp), sessiontimezone) at time zone 'GMT') as date) -- in_date cast do GMT
          - 
          TO_DATE('01.01.1970','dd.mm.yyyy') -- minus unix start date
        )
        * 86400000 -- times miliseconds in day
        from dual;
    

    【讨论】:

    • 这里也是:当查询在夏季运行时 sessiontimezone 可能会有所不同,但转换应该在冬季转换日期......请参阅下面的答案以获得更好的解决方案。
    【解决方案5】:

    这是我想出的:

    select    substr(extract(day from (n.origstamp - timestamp '1970-01-01 00:00:00')) * 24 * 60 * 60 + 
              extract(hour from (n.origstamp - timestamp '1970-01-01 00:00:00')) * 60 * 60 + 
              extract(minute from (n.origstamp - timestamp '1970-01-01 00:00:00')) * 60 + 
              trunc(extract(second from (n.origstamp - timestamp '1970-01-01 00:00:00')),0),0,15) TimeStamp 
              from tablename;
    

    FWIW

    【讨论】:

      【解决方案6】:
      SELECT (SYSDATE - TO_DATE('01-01-1970 00:00:00', 'DD-MM-YYYY HH24:MI:SS')) * 24 * 60 * 60 * 1000 FROM DUAL
      

      【讨论】:

        【解决方案7】:

        对于 Oracle 时间和 Unix 时间之间的转换,我使用这些函数。 他们会考虑您当前的时区。您还应该添加 DETERMINISTIC 关键字,例如,如果您想在基于函数的索引中使用此类函数。 DATETIMESTAMP 之间的转换应该由 Oracle 隐式完成。

        FUNCTION Timestamp2UnixTime(theTimestamp IN TIMESTAMP, timezone IN VARCHAR2 DEFAULT SESSIONTIMEZONE) RETURN NUMBER DETERMINISTIC IS
            timestampUTC TIMESTAMP;
            theInterval INTERVAL DAY(9) TO SECOND;
            epoche NUMBER;
        BEGIN
            timestampUTC := FROM_TZ(theTimestamp, timezone) AT TIME ZONE 'UTC';
            theInterval := TO_DSINTERVAL(timestampUTC - TIMESTAMP '1970-01-01 00:00:00');
            epoche := EXTRACT(DAY FROM theInterval)*24*60*60 
                + EXTRACT(HOUR FROM theInterval)*60*60 
                + EXTRACT(MINUTE FROM theInterval)*60 
                + EXTRACT(SECOND FROM theInterval);
            RETURN ROUND(epoche);
        END Timestamp2UnixTime;
        
        
        
        FUNCTION UnixTime2Timestamp(UnixTime IN NUMBER) RETURN TIMESTAMP DETERMINISTIC IS
        BEGIN
            RETURN (TIMESTAMP '1970-01-01 00:00:00 UTC' + UnixTime * INTERVAL '1' SECOND) AT LOCAL;
        END UnixTime2Timestamp;
        

        【讨论】:

        • 这似乎给出了微秒而不是秒。
        • @GPHemsley,有些系统使用秒数,有些系统使用毫秒数。如何改变它应该是相当明显的。
        • 标准 Unix 时间戳以纪元以来的秒数为单位,问题并不表明需要对该标准进行任何更改。这个问题的所有其他答案都使用秒,而不是毫秒(这就是我的意思,而不是微秒)。如何更改答案可能相当明显,但从一开始就需要更改答案并不是很明显。
        【解决方案8】:

        我同意 Wernfried DomscheitJames Sumners 在他们的帖子中解释的解决方案 - 主要是因为时区和夏令时/冬令时问题!

        我更喜欢更短且没有动态 SQL 的函数之一:

        -- as Date 
        CAST ( FROM_TZ( TIMESTAMP '1970-01-01 00:00:00' + NUMTODSINTERVAL(input_date , 'SECOND') , 'GMT' ) AT TIME ZONE 'Europe/Berlin' AS DATE )
        

        -- as Timestamp
        FROM_TZ( to_timestamp(Date '1970-01-01' + input_date / 86400 ), 'GMT' ) AT TIME ZONE 'Europe/Berlin'
        

        作为“时区”,需要放置静态字符串(即“欧洲/柏林”)而不是 dbtimezone 或 sessiontimezone 变量,因为这可能会产生错误的偏移量,因为执行时间可能在夏季,而 unix Timestamp可能在冬天。

        【讨论】:

          【解决方案9】:

          以上所有都这样做:-

          ORA-01873: 区间的前导精度太小

          如果您的日期是 TIMESTAMP 格式。

          这是正确答案(假设您足够聪明,可以将服务器设置为使用 UTC。)

          select (cast(sys_extract_utc(current_timestamp) as date) - TO_DATE('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')) * 86400 as gmt_epoch from dual;
          

          【讨论】:

            【解决方案10】:
            SELECT 
            to_char(sysdate, 'YYYY/MM/DD HH24:MI:SS') dt,
            round((sysdate - to_date('19700101 000000', 'YYYYMMDD HH24MISS'))*86400) as udt 
            FROM dual; 
            

            【讨论】:

            • 始终建议在您的代码中添加一些解释,特别是如果已经有很多答案,为什么它与其他答案不同
            • 不考虑闰年、闰秒
            猜你喜欢
            • 2013-02-14
            • 2015-10-07
            • 2013-04-07
            • 1970-01-01
            • 2020-10-19
            • 1970-01-01
            • 2023-03-18
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多