【问题标题】:Oracle SQL Date to Long and vice versaOracle SQL Date to Long,反之亦然
【发布时间】:2013-07-08 06:57:19
【问题描述】:

我有以下将长数转换为日期的 SQL 查询,我无法将日期转换回长数。请告诉我您的建议。

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

输出

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


输出
1432549301782839296

long 值不一样。

【问题讨论】:

  • 您的直接问题是精度;第一次选择的日期有一个时间部分,当你转换回来时,你会丢失它;它应该是09-JUL-2013 01:13:19。但作为时间戳,它转到01:13:19.775670462。您需要多少精度,power 操作从何而来 - 数值的来源是什么?
  • @Alex:这个逻辑是一年前写的,我也对权力操纵感到困惑,这有什么意义。
  • @Alex:你能告诉我你是如何从号码中提取“01:13:19.775670462”的吗?

标签: sql oracle date unix-timestamp


【解决方案1】:

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

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

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 风格的纪元日期,从你使用的纪元日期算起的秒数或有时毫秒数,如果它必须存储为数字的话。这个设计……很有趣。

【讨论】:

  • 感谢您的回答。我已经给出了最大的精确度。很好理解并感谢您的努力和时间。
【解决方案2】:

尝试使用以下查询:

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

【讨论】:

  • 你能试试 SELECT TO_NUMBER(TO_CHAR(SYSDATE, 'J')) FROM DUAL;询问?我现在没有 Oracle 访问权限。
猜你喜欢
  • 2020-07-08
  • 2011-09-03
  • 1970-01-01
  • 1970-01-01
  • 2014-05-11
  • 2021-09-28
  • 2019-12-27
  • 2014-11-08
  • 2012-02-16
相关资源
最近更新 更多