在Oracle中两个DATE时间相减,得到的两个时间相差的天数。由于Oracle保存的单位是天而不是秒,因此难免造成误差。
一般来说这个误差可能并不明显,但是如果读取的变量精度足够,就能看到这个误差的存在:
SQL> select (to_date('2009-2-3 23:28:14', 'yyyy-mm-dd hh24:mi:ss')
2 - to_date('2009-2-3 22:58:14', 'yyyy-mm-dd hh24:mi:ss')) * 86400 seconds
3 from dual;
SECONDS
----------
1800
SQL> set serverout on
SQL> begin
2 dbms_output.put_line((to_date('2009-2-3 23:28:14', 'yyyy-mm-dd hh24:mi:ss')
3 - to_date('2009-2-3 22:58:14', 'yyyy-mm-dd hh24:mi:ss')) * 86400);
4 end;
5 /
1799.999999999999999999999999999999999997
PL/SQL procedure successfully completed.
这对于要分别获取时、分、秒信息的情况,可能会造成影响:
SQL> with a as
2 (select to_date('2009-2-3 23:28:14', 'yyyy-mm-dd hh24:mi:ss')
3 - to_date('2009-2-3 22:58:14', 'yyyy-mm-dd hh24:mi:ss') day
4 from dual)
5 select trunc(day * 24) || '时'
6 || mod(trunc(day * 1440), 60) || '分'
7 || mod(trunc(day * 86400), 60) || '秒'
8 from a;
TRUNC(DAY*2
-----------
0时29分59秒
为了解决这个问题,只有在获取到秒的时候就进行四舍五入:
SQL> with a as
2 (select round((to_date('2009-2-3 23:28:14', 'yyyy-mm-dd hh24:mi:ss')
3 - to_date('2009-2-3 22:58:14', 'yyyy-mm-dd hh24:mi:ss'))*86400) second
4 from dual)
5 select trunc(second / 3600) || '时'
6 || mod(trunc(second / 60), 60) || '分'
7 || mod(second, 60) || '秒'
8 from a;
TRUNC(SECO
----------
0时30分0秒
除了上面的方法外,其实利用INTERVAL也是很方便的。
在Oracle中,两个TIMESTAMP类型相减得到的就是INTERVAL:
SQL> with a as
2 (select to_timestamp('2009-2-3 23:28:14', 'yyyy-mm-dd hh24:mi:ss')
3 - to_timestamp('2009-2-3 22:58:14', 'yyyy-mm-dd hh24:mi:ss') inter
4 from dual)
5 select extract (hour from inter) || '时'
6 || extract (minute from inter) || '分'
7 || extract (second from inter) || '秒' result
8 from a;
RESULT
---------------------------------------------------------------------------------------
0时30分0秒
对于DATE类型,可以通过TO_TIMESTAMP(TO_CHAR())的方式转换为TIMESTAMP类型。