sql >> データベース >  >> RDS >> Oracle

Oracleでミリ秒単位のタイムスタンプを日付に変換する方法

    エポックからのミリ秒から日付に変換する必要がある場合は、次のようにします。

    SELECT TIMESTAMP '1970-01-01 00:00:00.000'
             + NUMTODSINTERVAL( 1483228800000 / 1000, 'SECOND' )
             AS TIME
    FROM   DUAL
    

    どの出力:

    TIME
    -----------------------
    2017-01-01 00:00:00.000
    

    年月が必要な場合は、TRUNC( timestamp, 'MM' )を使用します またはTO_CHAR( timestamp, 'YYYY-MM' )

    うるう秒を処理する必要がある場合は、これを考慮してエポック時間を調整するユーティリティパッケージを作成できます。

    CREATE OR REPLACE PACKAGE time_utils
    IS
      FUNCTION milliseconds_since_epoch(
        in_datetime  IN TIMESTAMP,
        in_epoch     IN TIMESTAMP DEFAULT TIMESTAMP '1970-01-01 00:00:00'
      ) RETURN NUMBER;
    
      FUNCTION milliseconds_epoch_to_ts (
        in_milliseconds IN NUMBER,
        in_epoch        IN TIMESTAMP DEFAULT TIMESTAMP '1970-01-01 00:00:00'
      ) RETURN TIMESTAMP;
    END;
    /
    SHOW ERRORS;
    
    CREATE OR REPLACE PACKAGE BODY time_utils
    IS
      -- List of the seconds immediately following leap seconds:
      leap_seconds CONSTANT SYS.ODCIDATELIST := SYS.ODCIDATELIST(
          DATE '1972-07-01',
          DATE '1973-01-01',
          DATE '1974-01-01',
          DATE '1975-01-01',
          DATE '1976-01-01',
          DATE '1977-01-01',
          DATE '1978-01-01',
          DATE '1979-01-01',
          DATE '1980-01-01',
          DATE '1981-07-01',
          DATE '1982-07-01',
          DATE '1983-07-01',
          DATE '1985-07-01',
          DATE '1988-01-01',
          DATE '1990-01-01',
          DATE '1991-01-01',
          DATE '1992-07-01',
          DATE '1993-07-01',
          DATE '1994-07-01',
          DATE '1996-01-01',
          DATE '1997-07-01',
          DATE '1999-01-01',
          DATE '2006-01-01',
          DATE '2009-01-01',
          DATE '2012-07-01',
          DATE '2015-07-01',
          DATE '2016-01-01'
        );
    
      HOURS_PER_DAY           CONSTANT BINARY_INTEGER := 24;
      MINUTES_PER_HOUR        CONSTANT BINARY_INTEGER := 60;
      SECONDS_PER_MINUTE      CONSTANT BINARY_INTEGER := 60;
      MILLISECONDS_PER_SECOND CONSTANT BINARY_INTEGER := 1000;
    
      MINUTES_PER_DAY         CONSTANT BINARY_INTEGER := HOURS_PER_DAY   * MINUTES_PER_HOUR;
      SECONDS_PER_DAY         CONSTANT BINARY_INTEGER := MINUTES_PER_DAY * SECONDS_PER_MINUTE;
    
      MILLISECONDS_PER_MINUTE CONSTANT BINARY_INTEGER := SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND;
      MILLISECONDS_PER_HOUR   CONSTANT BINARY_INTEGER := MINUTES_PER_HOUR   * MILLISECONDS_PER_MINUTE;
      MILLISECONDS_PER_DAY    CONSTANT BINARY_INTEGER := HOURS_PER_DAY      * MILLISECONDS_PER_HOUR;
    
      FUNCTION milliseconds_since_epoch(
        in_datetime  IN TIMESTAMP,
        in_epoch     IN TIMESTAMP DEFAULT TIMESTAMP '1970-01-01 00:00:00'
      ) RETURN NUMBER
      IS
        p_leap_milliseconds BINARY_INTEGER := 0;
        p_diff              INTERVAL DAY(9) TO SECOND(3);
      BEGIN
        IF in_datetime IS NULL OR in_epoch IS NULL THEN
          RETURN NULL;
        END IF;
    
        p_diff := in_datetime - in_epoch;
    
        IF in_datetime >= in_epoch THEN
          FOR i IN 1 .. leap_seconds.COUNT LOOP
            EXIT WHEN in_datetime < leap_seconds(i);
            IF in_epoch < leap_seconds(i) THEN
              p_leap_milliseconds := p_leap_milliseconds + MILLISECONDS_PER_SECOND;
            END IF;
          END LOOP;
        ELSE
          FOR i IN REVERSE 1 .. leap_seconds.COUNT LOOP
            EXIT WHEN in_datetime > leap_seconds(i);
            IF in_epoch > leap_seconds(i) THEN
              p_leap_milliseconds := p_leap_milliseconds - MILLISECONDS_PER_SECOND;
            END IF;
          END LOOP;
        END IF;
    
        RETURN   MILLISECONDS_PER_SECOND * EXTRACT( SECOND FROM p_diff )
               + MILLISECONDS_PER_MINUTE * EXTRACT( MINUTE FROM p_diff )
               + MILLISECONDS_PER_HOUR   * EXTRACT( HOUR   FROM p_diff )
               + MILLISECONDS_PER_DAY    * EXTRACT( DAY    FROM p_diff )
               + p_leap_milliseconds;
      END milliseconds_since_epoch;
    
      FUNCTION milliseconds_epoch_to_ts(
        in_milliseconds IN NUMBER,
        in_epoch        IN TIMESTAMP DEFAULT TIMESTAMP '1970-01-01 00:00:00'
      ) RETURN TIMESTAMP
      IS
        p_datetime TIMESTAMP;
      BEGIN
        IF in_milliseconds IS NULL OR in_epoch IS NULL THEN
          RETURN NULL;
        END IF;
    
        p_datetime := in_epoch
            + NUMTODSINTERVAL( in_milliseconds / MILLISECONDS_PER_SECOND, 'SECOND' );
    
        IF p_datetime >= in_epoch THEN
          FOR i IN 1 .. leap_seconds.COUNT LOOP
            EXIT WHEN p_datetime < leap_seconds(i);
            IF in_epoch < leap_seconds(i) THEN
              p_datetime := p_datetime - INTERVAL '1' SECOND;
            END IF;
          END LOOP;
        ELSE
          FOR i IN REVERSE 1 .. leap_seconds.COUNT LOOP
            EXIT WHEN p_datetime > leap_seconds(i);
            IF in_epoch > leap_seconds(i) THEN
              p_datetime := p_datetime + INTERVAL '1' SECOND;
            END IF;
          END LOOP;
        END IF;
    
        RETURN p_datetime;
      END milliseconds_epoch_to_ts;
    END;
    /
    SHOW ERRORS;
    

    次に、次のことができます:

    SELECT TIME_UTILS.milliseconds_epoch_to_ts(
             in_milliseconds => 1483228800000,
             in_epoch        => TIMESTAMP '1970-00-00 00:00:00.000'
           ) AS time
    FROM DUAL;
    

    そして、出力を取得します:

    TIME
    -----------------------
    2016-12-31 23:59:33.000
    

    注:新しいうるう秒が提案された場合は、パッケージを最新の状態に保つ必要があります。

    更新

    SELECT COUNT(*) "EVENTS",
           TRUNC(
             TIMESTAMP '1970-01-01 00:00:00.000'
               + NUMTODSINTERVAL( MSSTAMP / 1000, 'SECOND' ),
             'MM'
           ) "FINISHED_MONTH"
    FROM   DB_TABLE
    WHERE  MSSTAMP < 1483228800000
    AND    STATUS = 'FINISHED'
    GROUP BY
           TRUNC(
             TIMESTAMP '1970-01-01 00:00:00.000'
               + NUMTODSINTERVAL( MSSTAMP / 1000, 'SECOND' ),
             'MM'
           );
    



    1. 一意の列でnullを許可する

    2. OracleにSKIPLOCKEDでTOPN行を返すように強制します

    3. シーケンス番号mysqlで列を更新する

    4. T-SQLの週番号から日付を取得する