web-dev-qa-db-ja.com

Oracleで2つの日付を減算して結果を時と分で取得する方法

2つの日付を減算し、結果を時間と分で10進数の1桁で表します。

次の表があり、この方法で実行していますが、結果は期待どおりではありません。

若干のばらつきがありますが、これは単純な算術演算であると確信していますが、正しく理解していません。

select start_time, end_time, (end_time-start_time)*24 from 
come_leav;    
 
 START_TIME END_TIME(END_TIME-START_TIME)* 24 
 ------------------- ------- ------------ ------------------------ 
 21-06-2011 14:00: 00 21-06-2011 16:55:00 2.9166667 
 21-06-2011 07:00:00 21-06-2011 16:50:00 9.8333333 
 21-06-2011 07: 20:00 21-06-2011 16:30:00 9.1666667 
 

次のような結果(end_time-start_time)が必要です。

 16:55- 14:00 = 2.55 
 16:50-07:00 = 9.5 
 16:30-7:20 = 9.1など。 

どうやってやるの?

9
Macky
SQL> edit
Wrote file afiedt.buf

  1  select start_date
  2      , end_date
  3      , (24 * extract(day from (end_date - start_date) day(9) to second))
  4          + extract(hour from (end_date - start_date) day(9) to second)
  5          + ((1/100) * extract(minute from (end_date - start_date) day(9) to second)) as "HOUR.MINUTE"
  6* from t
SQL> /

START_DATE          END_DATE            HOUR.MINUTE
------------------- ------------------- -----------
21-06-2011 14:00:00 21-06-2011 16:55:00        2.55
21-06-2011 07:00:00 21-06-2011 16:50:00         9.5
21-06-2011 07:20:00 21-06-2011 16:30:00         9.1

このコードに出くわす人にとって、小数部分は実際の分差であり、1時間の一部ではないことに注意してください。したがって、.550 minutesではなく30 minutesを表します。

4

これを試して

round(to_number(end_time - start_time) * 24)
2
reader_1000

Oracleは日付を日数で表すため、_(end_time-start_time)*24_は時間を示します。 h列にこの番号(例:_2.9166667_)があるとします。その後、FLOOR(h) + (h-FLOOR(h))/100*60を使用して簡単に必要な形式に変換できます。

例:

_WITH diff AS (
    SELECT (TO_DATE('21-06-2011 16:55:00', 'DD-MM-YYYY HH24:MI:SS') - TO_DATE('21-06-2011 14:00:00', 'DD-MM-YYYY HH24:MI:SS'))*24 h
    FROM dual
) SELECT FLOOR(h) + (h-FLOOR(h))/100*60
FROM diff
_

あなたの場合:

_SELECT start_time, end_time,
    FLOOR((end_time-start_time)*24) + ((end_time-start_time)*24-FLOOR((end_time-start_time)*24))/100*60 AS hours_diff
FROM come_leav 
_
2
Crack

これは非常に醜い方法であり、この最初の部分はOPによって正確に質問されるわけではありませんが、2つの日付フィールド(私の場合はCREATED_DATE)と今日を差し引くことによって結果を得る方法を提供しますSYSDATEで表されます:

SELECT FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE)) / 12) || ' years, '  
|| (FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE))) - 
   (FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE)) / 12)) * 12) || ' months, '  
-- we take total days - years(as days) - months(as days) to get remaining days
|| FLOOR((SYSDATE - CREATED_DATE) -      -- total days
   (FLOOR((SYSDATE - CREATED_DATE)/365)*12)*(365/12) -      -- years, as days
   -- this is total months - years (as months), to get number of months, 
   -- then multiplied by 30.416667 to get months as days (and remove it from total days)
   FLOOR(FLOOR(((SYSDATE - CREATED_DATE)/365)*12 - (FLOOR((SYSDATE - CREATED_DATE)/365)*12)) * (365/12)))  
|| ' days, '   
-- Here, we can just get the remainder decimal from total days minus 
-- floored total days and multiply by 24       
|| FLOOR(
     ((SYSDATE - CREATED_DATE)-(FLOOR(SYSDATE - CREATED_DATE)))*24
   )
|| ' hours, ' 
-- Minutes just use the unfloored hours equation minus floored hours, 
-- then multiply by 60
|| ROUND(
       (
         (
           ((SYSDATE - CREATED_DATE)-(FLOOR(SYSDATE - CREATED_DATE)))*24
         ) - 
         FLOOR((((SYSDATE - CREATED_DATE)-(FLOOR(SYSDATE - CREATED_DATE)))*24))
       )*60
    )
|| ' minutes'  
AS AGE FROM MyTable`

X年、xか月、x日、x時間、x分として出力を提供します。連結された文字列を変更することで、好みに応じて再フォーマットできます。

質問にもっと直接答えるために、私は先に進んでhours.minutesのように分で合計時間を取得する方法を書きました:

select  
((FLOOR(end_date - start_date))*24)
|| '.' ||
ROUND(
       (
         (
           ((end_date - start_date)-(FLOOR(end_date - start_date)))*24
         ) - 
         FLOOR((((end_date - start_date)-(FLOOR(end_date - start_date)))*24))
       )*60
    )
from 
come_leav;   
0
vapcguy

編集:番号が必要な場合は、

_    trunc(end_date-start_date)*24+
    to_number(to_char(trunc(sysdate)+(end_date-start_date),'HH24.MI'))
_

文字列の結果について、deltaが24H未満の場合:私は

_    to_char(trunc(sysdate)+(end_date-start_date),'HH24.MI')
_

または_...'HH24:MI:SS'_ですが、それは私の個人的な好みです。

24時間より長い用語の場合は、

_    trunc(end_date-start_date)||"days "||
    to_char(trunc(sysdate)+(end_date-start_date),'HH24.MI')
_

はい、Oracleは日単位で数秒の精度でカウントするため、算術演算の問題を処理しています。一度は分のみを処理しているため(つまり、数値をtrunc(days*24*60+0.5)/24/60に丸める可能性があります)、数値1/24/60の2進算術の不正確さが依然として問題を引き起こす可能性があります。

Edit2.1:

_    to_char(24*(trunc(end_date)-trunc(start_date))+to_number(to_char(end_date,'HH24.MI'))-to_number(to_char(start_date,'HH24.MI')),'99999.99')
_

ただし、10進の7.50は7時間10分の経過時間とは対照的に、7時間半、または少なくとも7時間50分を示唆するため、結果は平均をかなり混乱させる可能性があります。

0
vmatyi

これを試して:

    SELECT
    TRIM(TO_CHAR(TRUNC(((86400*(end_time - start_time))/60)/60)-24*(trunc((((86400*(end_time - start_time))/60)/60)/24)),'00')) ||'.'||
    TRIM(TO_CHAR(TRUNC((86400*(end_time - start_time))/60)-60*(trunc(((86400*(end_time - start_time))/60)/60)),'00')) ||'.'  as duration
FROM come_leav;
0
Kevin Burton

このクエリは私にとって非常に便利です。HH:MI:SSのように、開始日と終了日との時間の差が必要な場合は、このクエリを使用してください。

SELECT
    TRIM(TO_CHAR(TRUNC(((86400*(end_date - start_date))/60)/60)-24*(trunc((((86400(end_date - start_date))/60)/60)/24)),'00')) ||'.'||
    TRIM(TO_CHAR(TRUNC((86400*(actual_completion_date - actual_start_date))/60)-60*(trunc(((86400*(end_date - start_date))/60)/60)),'00')) ||'.'||
    TRIM(TO_CHAR(TRUNC((86400*(end_date - start_date)))-60*(trunc((86400*(end_date - actual_start_date))/60)),'00')) as duration  
FROM fnd_concurrent_requests; 
0