您在转换中失去了太多的精度,无法以另一种方式返回。您可以通过使用时间戳而不是日期来更接近。
首先,您的初始查询完全丢失了时间部分:
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
...但即便如此,转换回来已经失去了太多:
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
这比你得到的 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
通过时间戳算术给出间隔结果将其转换回来很复杂,然后您必须对其进行操作以返回一个数字,首先是原始天数:
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
...然后用你的权力操纵:
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
这非常接近。您可以将其截断或四舍五入到最接近的整数。
仅查看您的数字和每种方式的权力操纵表明它似乎在 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...
即使有时间戳,你也会丢失一些,因为第一个值超过了 9 位小数秒的限制。代表小数秒的部分 - 一旦你考虑了 15895 小时等 - 是.0000089776673785814232865555418862
一天,也就是.77567046150943497195839881896768
秒;时间戳将其四舍五入为.775670462
. 所以它永远不会是完美的。
这也导致人们想知道原始数字是如何生成的;看起来它实际上不太可能代表一个极端精确的时间,因为它低于yoctoseconds。目前还不清楚“精度”是否实际上是基于 2 的幂次方对其进行操纵的人工制品,但无论如何它看起来并不是很有用。更常见的是使用 Unix 风格的纪元日期,从你使用的纪元日期算起的秒数或有时毫秒数,如果它必须存储为数字的话。这个设计……很有趣。