2009-05-27 149 views
3

這個調用 -Oracle日期四捨五入

SELECT ((TO_DATE ('06/06/2009 16:00:00', 'DD/MM/YYYY HH24:MI:SS') - TO_DATE ('06/06/2009 14:25:00', 'DD/MM/YYYY HH24:MI:SS')) * 1440.000) from dual

可生產95的結果 - 這是你從計算的期望。

這個調用 -

SELECT trunc((TO_DATE ('06/06/2009 16:00:00', 'DD/MM/YYYY HH24:MI:SS') - TO_DATE ('06/06/2009 14:25:00', 'DD/MM/YYYY HH24:MI:SS')) * 1440.000) from dual

產生的94

結果的修復建議是 - SELECT trunc((TO_DATE ('06/06/2009 16:00:00', 'DD/MM/YYYY HH24:MI:SS') - TO_DATE ('06/06/2009 14:25:00', 'DD/MM/YYYY HH24:MI:SS')) * 1440.000+.00001) from dual

該解決方案似乎是錯誤的我 - 任何人都可以提出一個更好的選擇?實際的要求是計算兩個日期之間的整個分鐘差異。

回答

4

優秀的問題。

由於此處的數據類型轉換,日期算術不完全準確。

TO_DATE('06/06/2009 16:00:00', 'DD/MM/YYYY HH24:MI:SS') 
- TO_DATE('06/06/2009 14:25:00', 'DD/MM/YYYY HH24:MI:SS')) 
= .0659722222222222222222222222222222222222000000000000000 

.0659722222222222222222222222222222222222000000000000000 
* 1440 
=94.9999999999999999999999999999999999999700000000000 

這意味着沒有TRUNC,圓,CEIL和地板將在所有情況下工作。

爲了解決這個問題,你需要能夠將每個日期轉換爲整數在其上進行算術運算之前,例如:

select FLOOR((TO_CHAR(TO_DATE('06/06/2009 16:00:00', 'DD/MM/YYYY HH24:MI:SS'),'J') * 1440 
+ TO_CHAR(TO_DATE('06/06/2009 16:00:00', 'DD/MM/YYYY HH24:MI:SS'),'SSSSS')/60) 
- (TO_CHAR(TO_DATE('06/06/2009 14:25:00', 'DD/MM/YYYY HH24:MI:SS'),'J') * 1440 
+ TO_CHAR(TO_DATE('06/06/2009 14:25:00', 'DD/MM/YYYY HH24:MI:SS'),'SSSSS')/60)) 
from dual; 
+1

您可以告訴TRUNC或ROUND達到一定的小數位數。五個可能足以應付四捨五入的錯誤。 select trunc(94.999999999999999999999,5)from dual; – 2009-05-27 06:52:37

+1

哎呦,我的意思是TRUNC和ROUND的組合,如 select trunc(round(94.99999999999999,5),2)from dual; – 2009-05-27 09:36:06

0

爲什麼不使用ROUND而不是TRUNC?它將結果應用到日期的最近的一天,應用於數字時最近的整數(TRUNC截斷,並且似乎在這裏遇到奇怪的算術問題)。

+0

要求是隻計算結果中的整個分鐘。 Round將無法正常工作59秒... – YogoZuno 2009-05-27 04:50:50

0

那麼,不是說它應該會更好,但你有沒有試過FLOOR來代替TRUNC? (在瘋狂的事件中,它可以工作,你可能想要測試結果是否爲負數,在這種情況下,你需要添加一個,因爲當TRUNC向零迴轉時,FLOOR「向四捨五入」轉向負無窮大。在使用TRUNC之前加入幾分之一秒不會更醜。)

4

忘記日期和使用時間戳。使用時間戳算術,Oracle使用INTERVAL數據類型來避免舍入問題。

select extract (minute from cast(later as timestamp) - cast(earlier as timestamp)) + 
     (extract (hour from cast(later as timestamp) - cast(earlier as timestamp)) * 60) 
from 
(select TO_DATE ('06/06/2009 16:00:00', 'DD/MM/YYYY HH24:MI:SS') later, 
     TO_DATE ('06/06/2009 14:25:00', 'DD/MM/YYYY HH24:MI:SS') earlier 
from dual) 
/

如果日期間隔超過一天,您還需要考慮這一點。