Sql 如何在Oracle中将毫秒时间戳转换为日期
我将MSSTAMP作为Oracle中的“毫秒时间戳”,格式为1483228800000。如何将毫秒时间戳转换为日期格式“YYYY-MM”,以便获得前几年每月完成的行数 我尝试了不同版本的TO_DATE、CAST和TO_CHAR,但我无法实现这一点Sql 如何在Oracle中将毫秒时间戳转换为日期,sql,oracle,Sql,Oracle,我将MSSTAMP作为Oracle中的“毫秒时间戳”,格式为1483228800000。如何将毫秒时间戳转换为日期格式“YYYY-MM”,以便获得前几年每月完成的行数 我尝试了不同版本的TO_DATE、CAST和TO_CHAR,但我无法实现这一点 select count(*) "EVENTS", TO_DATE(MSSTAMP, 'YYYY-MM') "FINISHED_MONTH" from DB_TABLE where MSSTAMP < '1483228800
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
选择
计数(*)“事件”,
截止日期(MSSTAMP,'YYYY-MM')“完成月份”
从…起
DB_表
哪里
MSSTAMP<'1483228800000'
及
状态为('FINISHED')
分组
完成月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')
或来显示字符(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;
并获得输出:
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'
);
选择计数(*)“事件”,
特鲁克(
时间戳“1970-01-01 00:00:00.000”
+NUMTODSINTERVAL(MSSTAMP/1000,“秒”),
“嗯”
)“完成一个月”
从DB_表
其中MSSTAMP<1483228800000
和状态='FINISHED'
分组
特鲁克(
时间戳“1970-01-01 00:00:00.000”
+NUMTODSINTERVAL(MSSTAMP/1000,“秒”),
“嗯”
);
这是一个彻底的答案,但我不明白如何在我的查询中实现这一点?(闰年、秒等目前不受关注。)我认为您对闰秒的处理是错误的,请参阅:Unix时代的Unix时间数字为零,自该时代以来每天增加86400。@WernfriedDomscheit我不想在闰秒实现中处理Unix时间(从未提及过Unix时间)-我试图处理实时问题,但每天并不总是有86400秒。如果您想处理Unix时间,那么只需使用top方法(它使用Oracle的时间戳
和间隔日到秒
实现,总是每分钟60秒)。是的,Unix时间甚至没有被提及,尽管很可能是基于给定的数字。
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'
);