我目前有一个SQL查询,该查询从数据库中的Unix DATETIME
列返回正确的本地TIMESTAMP
。
以下是使用TIMESTAMP
中的特定1539961967000
的示例:
SELECT FROM_TZ(CAST(DATE '1970-01-01' + 1539961967000 * (1/24/60/60/1000) AS TIMESTAMP), 'UTC') AT TIME ZONE 'America/Denver' DATETIME
FROM dual;
返回:
DATETIME
19-OCT-18 09.12.47.000000000 AM AMERICA/DENVER
我很难逆转此查询以返回以本地TIMESTAMP
开头的Unix DATETIME
。
以前有人遇到过吗?
答案 0 :(得分:2)
您可以将带有时区的时间戳转换为UTC,然后从中减去纪元:
select timestamp '2018-10-19 09:12:47.0 AMERICA/DENVER'
- timestamp '1970-01-01 00:00:00.0 UTC' as diff
from dual;
为您提供间隔数据类型:
DIFF
----------------------
+17823 15:12:47.000000
然后您可以从中提取元素,然后将每个元素乘以适当的因子以将其转换为毫秒(例如,天数为60 * 60 * 24 * 1000);然后将它们添加在一起:
select extract(day from diff) * 86400000
+ extract(hour from diff) * 3600000
+ extract(minute from diff) * 60000
+ extract(second from diff) * 1000 as unixtime
from (
select timestamp '2018-10-19 09:12:47.0 AMERICA/DENVER'
- timestamp '1970-01-01 00:00:00.0 UTC' as diff
from dual
);
UNIXTIME
--------------------
1539961967000
如果开始时间戳包含毫秒,它也会保留毫秒(这是从“ Unix”时间转换而保留的):
select (timestamp '1970-01-01 00:00:00.0 UTC' + (1539961967567 * interval '0.001' second))
at time zone 'America/Denver' as denver_time
from dual;
DENVER_TIME
--------------------------------------------
2018-10-19 09:12:47.567000000 AMERICA/DENVER
然后转换回去:
select extract(day from diff) * 86400000
+ extract(hour from diff) * 3600000
+ extract(minute from diff) * 60000
+ extract(second from diff) * 1000 as unixtime
from (
select timestamp '2018-10-19 09:12:47.567 AMERICA/DENVER'
- timestamp '1970-01-01 00:00:00.0 UTC' as diff
from dual
);
UNIXTIME
--------------------
1539961967567
如果起始时间戳的精度比后者高,那么您将需要截断(或舍入/舍入/上限/下标/投射)以避免产生非整数的结果;这个版本只是截断了提取的毫秒部分:
select diff,
extract(day from diff) * 86400000
+ extract(hour from diff) * 3600000
+ extract(minute from diff) * 60000
+ trunc(extract(second from diff) * 1000) as unixtime
from (
select timestamp '2018-10-19 09:12:47.123456789 AMERICA/DENVER'
- timestamp '1970-01-01 00:00:00.0 UTC' as diff
from dual
);
DIFF UNIXTIME
------------------------- --------------------
+17823 15:12:47.123456789 1539961967123
如果没有这种截断(或等效截断),您最终会得到1539961967123.456789
。
我忘记了the秒的差异;如果您需要/想要处理此问题,请see this answer。
答案 1 :(得分:2)
主要问题是Oracle有两种方法(至少)将秒数转换为秒间隔-使用函数或对间隔文字进行简单的算术运算-但没有直接方法反之。
在下面的两个查询中,我首先展示如何在不损失毫秒的情况下将UNIX时间戳(自大纪元以来的毫秒数)转换为Oracle时间戳。 (请参阅我在“问题”下的评论,其中指出您的方法将丢失毫秒。)然后,我将展示如何逆转该过程。
像您一样,我忽略了“ Unix时间戳”导致的“ UTC时间戳”和“ Unix时间戳”之间的差异,忽略了leap秒。您的企业必须确定这是否重要。
Unix时间戳到带有时区(保留毫秒)的Oracle时间戳:
with
inputs (unix_timestamp) as (
select 1539961967186 from dual
)
select from_tz(timestamp '1970-01-01 00:00:00'
+ interval '1' second * (unix_timestamp/1000), 'UTC')
at time zone 'America/Denver' as oracle_ts_with_timezone
from inputs
;
ORACLE_TS_WITH_TIMEZONE
--------------------------------------
2018-10-19 09:12:47.186 America/Denver
Oracle时间戳,时区为Unix时间戳(保留毫秒):
with
sample_data (oracle_ts_with_timezone) as (
select to_timestamp_tz('2018-10-19 09:12:47.186 America/Denver',
'yyyy-mm-dd hh24:mi:ss.ff tzr') from dual
)
select ( extract(second from ts)
+ (trunc(ts, 'mi') - date '1970-01-01') * (24 * 60 * 60)
) * 1000 as unix_timestamp
from ( select cast(oracle_ts_with_timezone at time zone 'UTC'
as timestamp) as ts
from sample_data
)
;
UNIX_TIMESTAMP
----------------
1539961967186