Oracle SQL Date to Long,反之亦然

Dea*_*mer 2 sql oracle date unix-timestamp

我有以下SQL查询将长号转换为日期,我无法将日期转换回长号.请让我知道你的建议.

SELECT to_date((( 1432550197431912935  - POWER(2,60)) /POWER(2,44)) + to_date('01-JAN-1970','DD-MON-YYYY')) from dual
Run Code Online (Sandbox Code Playgroud)

产量

2013年7月9日

select     TO_CHAR(((TO_DATE ('09-JUL-2013','DD-MON-YYYY') -to_date('01-JAN-1970','DD-MON-YYYY'))  * POWER(2,44) ) + POWER(2,60)) from dual
Run Code Online (Sandbox Code Playgroud)


产量
1432549301782839296

长值不一样.

Ale*_*ole 6

您在转换中失去了太多精确度,无法以其他方式返回.您可以通过使用时间戳而不是日期来更近距离.

首先,您的初始查询完全丢失了时间组件:

select to_char(date '1970-01-01'
  + (1432550197431912935 - power(2, 60))/power(2, 44), 'YYYY-MM-DD HH24:MI:SS')
from dual;

2013-07-09 01:13:19
Run Code Online (Sandbox Code Playgroud)

......但即使如此,转换回来的方式已经太过分了:

select ((to_date('2013-07-09 01:13:19','YYYY-MM-DD HH24:MI:SS')
  - date '1970-01-01') * power(2, 44)) + power(2, 60) from dual;

1432550197477589405
Run Code Online (Sandbox Code Playgroud)

这比你得到的1432549301782839296更接近,但还有很长的路要走.

问题的一部分是精度DATE,只有第二个.如果你使用,TIMESTAMP你可以非常接近; 你可以看到,所拥有的价值应该是非常精确的:

select timestamp '1970-01-01 00:00:00'
  + numtodsinterval((1432550197431912935 - power(2, 60))/power(2, 44), 'DAY')
from dual;

2013-07-09 01:13:18.775670462
Run Code Online (Sandbox Code Playgroud)

通过时间戳算法给出间隔结果,将后面的转换变得很复杂,然后您必须操作以返回到数字,首先是原始天数:

select extract(day from int_val)
  + extract(hour from int_val) / 24
  + extract(minute from int_val) / (24 * 60)
  + extract(second from int_val) / (24 * 60 * 60)
from (
select to_timestamp('2013-07-09 01.13.18.775670462', 'YYYY-MM-DD HH24:MI:SS.FF9')
  - timestamp '1970-01-01 00:00:00' as int_val from dual);

15895.0509117554451620370370370370370371
Run Code Online (Sandbox Code Playgroud)

......然后用你的力量操纵:

select ((extract(day from int_val)
    + extract(hour from int_val) / 24
    + extract(minute from int_val) / (24 * 60)
    + extract(second from int_val) / (24 * 60 * 60))
  * power(2, 44)) + power(2, 60)
as x
from (
select to_timestamp('2013-07-09 01.13.18.775670462', 'YYYY-MM-DD HH24:MI:SS.FF9')
  - timestamp '1970-01-01 00:00:00' as int_val from dual);

1432550197431912935.09988554676148148148
Run Code Online (Sandbox Code Playgroud)

这非常接近.您可以将其截断或舍入到最接近的整数.


只需查看您的数字和每种方式的功率操作,就会发现它似乎符合Oracle可以应对的精度:

select (1432550197431912935 - power(2, 60)) / power(2, 44)
from dual;

15895.050911755445156359201064333319664

select (15895.050911755445156359201064333319664 * power(2, 44)) + power(2, 60)
from dual;

1432550197431912935.000...
Run Code Online (Sandbox Code Playgroud)

即使有时间戳,你也会失去一些,因为第一个值超过了9位数的小数秒限制.代表小数秒的部分 - 一旦你占了15895小时等等 - 是.0000089776673785814232865555418862一天,即.77567046150943497195839881896768秒; 时间戳正在四舍五入到.775670462.所以它永远不会是完美的.

这也让人想知道原始数字是如何产生的; 它似乎不太可能实际上代表一个极端精度的时间,因为它低于yoctoseconds.目前尚不清楚"精确度"实际上是否是基于2的幂来操纵它的人工制品,但无论如何它看起来都不是很有用.使用Unix风格的纪元日期更为常见,无论如何,如果必须将其存储为数字,则计算自您正在使用的纪元日期以来的秒数或有时毫秒数.这个设计很有意思.