我在Oracle 中将MSSTAMP设置 为“带有毫秒的时间戳”,格式:1483228800000。如何将该毫秒时间戳转换为日期格式“ YYYY- MM”,以便获得前几年每月的已完成行数。
我尝试了TO_DATE,CAST,TO_CHAR的不同变体-但无法正常工作。
select count(*) "EVENTS", TO_DATE(MSSTAMP, 'YYYY-MM') "FINISHED_MONTH" from DB_TABLE where MSSTAMP < '1483228800000' and STATUS in ('FINISHED') group by FINISHED_MONTH ASC
如果您只需要将自纪元以来的毫秒数转换为日期,则:
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' )。
TRUNC( timestamp, 'MM' )
TO_CHAR( timestamp, 'YYYY-MM' )
如果您需要处理leap秒,则可以创建一个实用程序包,该实用程序包将调整纪元时间以解决此问题:
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
注意:建议使用新的leap秒时,您将需要使软件包保持最新。
更新 :
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' );