ISO-8601 字符串的 Unix 时间戳
Unix Timestamp to ISO-8601 String
我有一个名为 ACQDATA
的 Oracle table,它有一个字段 READDATETIME
,我在其中存储一个以毫秒为单位的 Unix 时间戳作为 INTEGER
(NUMBER(38)
)类型。
SQL> select READDATETIME from ACQDATA where ID=1000;
READDATETIME
____________
1.4793E+12
我需要 select 该值作为 ISO-8601 字符串 (YYYY-MM-DDTHH:MM:SS.mmm
):
SQL> select READDATETIME from ACQDATA where ID=1000;
READDATETIME
-------------------
1.4793E+12
我试过使用 TO_CHAR
转换它,但结果很乱:
SQL> select TO_CHAR(TO_DATE('1970-01-01','YYYY-MM-DD') + NUMTODSINTERVAL(READDATETIME, 'SECOND'), 'YYYY-MM-DD HH24:MI:SS') from ACQDATA where ID=1000;
Error at line 1:
ORA-01873: the leading precision of the interval is too small
感谢帮助。
您的 readdatetime
似乎以毫秒为单位。 Oracle 日期算法以天为基础,因此您需要将该数字转换为它代表的天数;一天是 86400 秒,所以是 86400000 毫秒:
with acqdata (id, readdatetime) as (
select 1000, 1479318995000 from dual
)
select to_char(date '1970-01-01' + (READDATETIME/86400000), 'YYYY-MM-DD"T"HH24:MI:SS')
from ACQDATA where ID=1000;
TO_CHAR(DATE'1970-0
-------------------
2016-11-16T17:56:35
T
添加为 a character literal。
SQL 开发人员默认以科学记数法显示如此大的数字。您可以使用 set numformat
更改默认值,或使用 to_char()
显示整个值:
select readdatetime, to_char(readdatetime, '9999999999999') as string
from ACQDATA where ID=1000;
READDATETIME STRING
------------ --------------
1.4793E+12 1479318995000
如果您的值有小数秒,所以最后三位数字不是零,您可以将日期转换为时间戳并添加小数部分;这还添加了 UTC 'Z' 指标以供娱乐:
with acqdata (id, readdatetime) as (
select 1000, 1479300462063 from dual
)
select to_char(cast(date '1970-01-01' + (readdatetime/86400000) as timestamp)
+ numtodsinterval(remainder(readdatetime, 1000)/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
from acqdata where id=1000;
TO_CHAR(CAST(DATE'1970-01-01'+
------------------------------
2016-11-16T12:47:42.063Z
或者没有中间 date
值,从时间戳文字开始:
with acqdata (id, readdatetime) as (
select 1000, 1479300462063 from dual
)
select to_char(timestamp '1970-01-01 00:00:00'
+ numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
from acqdata where id=1000;
TO_CHAR(TIMESTAMP'1970-0
------------------------
2016-11-16T12:47:42.063Z
正如@Wernfried 指出的那样,最好明确表明纪元时间是从 UTC 开始的:
alter session set time_zone='America/New_York';
with acqdata (readdatetime) as (
select 1479300462063 from dual
union all select 1467331200000 from dual
union all select 1467648000000 from dual
)
select readdatetime,
to_char(timestamp '1970-01-01 00:00:00' + numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3') as implicit,
to_char(cast(timestamp '1970-01-01 00:00:00' as timestamp with time zone)
+ numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') as local_offset,
to_char(timestamp '1970-01-01 00:00:00 UTC' + numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') as utc_offset,
to_char(timestamp '1970-01-01 00:00:00 UTC' + numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZR') as utc
from acqdata;
READDATETIME IMPLICIT LOCAL_OFFSET UTC_OFFSET UTC
-------------- ----------------------- ----------------------------- ----------------------------- --------------------------
1479300462063 2016-11-16T12:47:42.063 2016-11-16T12:47:42.063-05:00 2016-11-16T12:47:42.063+00:00 2016-11-16T12:47:42.063UTC
1467331200000 2016-07-01T00:00:00.000 2016-07-01T01:00:00.000-04:00 2016-07-01T00:00:00.000+00:00 2016-07-01T00:00:00.000UTC
1467648000000 2016-07-04T16:00:00.000 2016-07-04T17:00:00.000-04:00 2016-07-04T16:00:00.000+00:00 2016-07-04T16:00:00.000UTC
Alex 的回答并不完全正确。 Unix 时间戳始终基于 1970-01-01 00:00:00 UTC
除非您的会话在 UTC 时区运行,否则精确的解决方案如下:
select
TO_CHAR((TIMESTAMP '1970-01-01 00:00:00 UTC' + readdatetime/1000 * INTERVAL '1' SECOND) AT LOCAL, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')
from ACQDATA where ID=1000;
或
select
TO_CHAR((TIMESTAMP '1970-01-01 00:00:00' AT TIME ZONE 'UTC' + readdatetime/1000 * INTERVAL '1' SECOND) AT LOCAL, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')
from ACQDATA where ID=1000;
或者如果您更喜欢函数而不是文字:
select
TO_CHAR((TO_TIMESTAMP_TZ('1970-01-01 00:00:00 UTC', 'YYYY-MM-DD HH24:MI:SS TZR') + numtodsinterval(readdatetime/1000, 'SECOND')) AT LOCAL, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')
from ACQDATA where ID=1000;
我有一个名为 ACQDATA
的 Oracle table,它有一个字段 READDATETIME
,我在其中存储一个以毫秒为单位的 Unix 时间戳作为 INTEGER
(NUMBER(38)
)类型。
SQL> select READDATETIME from ACQDATA where ID=1000;
READDATETIME
____________
1.4793E+12
我需要 select 该值作为 ISO-8601 字符串 (YYYY-MM-DDTHH:MM:SS.mmm
):
SQL> select READDATETIME from ACQDATA where ID=1000;
READDATETIME
-------------------
1.4793E+12
我试过使用 TO_CHAR
转换它,但结果很乱:
SQL> select TO_CHAR(TO_DATE('1970-01-01','YYYY-MM-DD') + NUMTODSINTERVAL(READDATETIME, 'SECOND'), 'YYYY-MM-DD HH24:MI:SS') from ACQDATA where ID=1000;
Error at line 1:
ORA-01873: the leading precision of the interval is too small
感谢帮助。
您的 readdatetime
似乎以毫秒为单位。 Oracle 日期算法以天为基础,因此您需要将该数字转换为它代表的天数;一天是 86400 秒,所以是 86400000 毫秒:
with acqdata (id, readdatetime) as (
select 1000, 1479318995000 from dual
)
select to_char(date '1970-01-01' + (READDATETIME/86400000), 'YYYY-MM-DD"T"HH24:MI:SS')
from ACQDATA where ID=1000;
TO_CHAR(DATE'1970-0
-------------------
2016-11-16T17:56:35
T
添加为 a character literal。
SQL 开发人员默认以科学记数法显示如此大的数字。您可以使用 set numformat
更改默认值,或使用 to_char()
显示整个值:
select readdatetime, to_char(readdatetime, '9999999999999') as string
from ACQDATA where ID=1000;
READDATETIME STRING
------------ --------------
1.4793E+12 1479318995000
如果您的值有小数秒,所以最后三位数字不是零,您可以将日期转换为时间戳并添加小数部分;这还添加了 UTC 'Z' 指标以供娱乐:
with acqdata (id, readdatetime) as (
select 1000, 1479300462063 from dual
)
select to_char(cast(date '1970-01-01' + (readdatetime/86400000) as timestamp)
+ numtodsinterval(remainder(readdatetime, 1000)/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
from acqdata where id=1000;
TO_CHAR(CAST(DATE'1970-01-01'+
------------------------------
2016-11-16T12:47:42.063Z
或者没有中间 date
值,从时间戳文字开始:
with acqdata (id, readdatetime) as (
select 1000, 1479300462063 from dual
)
select to_char(timestamp '1970-01-01 00:00:00'
+ numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
from acqdata where id=1000;
TO_CHAR(TIMESTAMP'1970-0
------------------------
2016-11-16T12:47:42.063Z
正如@Wernfried 指出的那样,最好明确表明纪元时间是从 UTC 开始的:
alter session set time_zone='America/New_York';
with acqdata (readdatetime) as (
select 1479300462063 from dual
union all select 1467331200000 from dual
union all select 1467648000000 from dual
)
select readdatetime,
to_char(timestamp '1970-01-01 00:00:00' + numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3') as implicit,
to_char(cast(timestamp '1970-01-01 00:00:00' as timestamp with time zone)
+ numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') as local_offset,
to_char(timestamp '1970-01-01 00:00:00 UTC' + numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') as utc_offset,
to_char(timestamp '1970-01-01 00:00:00 UTC' + numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZR') as utc
from acqdata;
READDATETIME IMPLICIT LOCAL_OFFSET UTC_OFFSET UTC
-------------- ----------------------- ----------------------------- ----------------------------- --------------------------
1479300462063 2016-11-16T12:47:42.063 2016-11-16T12:47:42.063-05:00 2016-11-16T12:47:42.063+00:00 2016-11-16T12:47:42.063UTC
1467331200000 2016-07-01T00:00:00.000 2016-07-01T01:00:00.000-04:00 2016-07-01T00:00:00.000+00:00 2016-07-01T00:00:00.000UTC
1467648000000 2016-07-04T16:00:00.000 2016-07-04T17:00:00.000-04:00 2016-07-04T16:00:00.000+00:00 2016-07-04T16:00:00.000UTC
Alex 的回答并不完全正确。 Unix 时间戳始终基于 1970-01-01 00:00:00 UTC
除非您的会话在 UTC 时区运行,否则精确的解决方案如下:
select
TO_CHAR((TIMESTAMP '1970-01-01 00:00:00 UTC' + readdatetime/1000 * INTERVAL '1' SECOND) AT LOCAL, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')
from ACQDATA where ID=1000;
或
select
TO_CHAR((TIMESTAMP '1970-01-01 00:00:00' AT TIME ZONE 'UTC' + readdatetime/1000 * INTERVAL '1' SECOND) AT LOCAL, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')
from ACQDATA where ID=1000;
或者如果您更喜欢函数而不是文字:
select
TO_CHAR((TO_TIMESTAMP_TZ('1970-01-01 00:00:00 UTC', 'YYYY-MM-DD HH24:MI:SS TZR') + numtodsinterval(readdatetime/1000, 'SECOND')) AT LOCAL, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')
from ACQDATA where ID=1000;