トップページに戻る    次のSQLパズルへ    前のSQLパズルへ

7-26 経過時間を取得(高精度)

SQLパズル

任意の日付から、現在までの経過時間を
日、時間、分、秒
で求める。


SQL

declare
    FromDate constant date := to_date('2005/08/01 23:30:00','YYYY/MM/DD HH24:MI:SS');
    ToDate date;

    日   varchar2(2);
    時間 varchar2(2);
    分   varchar2(2);
    秒   varchar2(2);
begin
    for i in 80000..90000 loop

        ToDate:= FromDate + i/24/60/60;

        select extract(day from NumToDsInterval(ToDate-FromDate,'day')) as 日,
        case when FromS < ToS then trunc((ToS-FromS)/3600)
             when FromS > ToS then trunc((24*60*60-FromS+ToS)/3600)
             else 0 end as 時間,
        case when FromS < ToS then trunc(mod(ToS-FromS,3600)/60)
             when FromS > ToS then trunc(mod(24*60*60-FromS+ToS,3600)/60)
             else 0 end as 分,
        case when FromS < ToS then mod(ToS-FromS,60)
             when FromS > ToS then mod(24*60*60-FromS+ToS,60)
             else 0 end as 秒
        into 日,時間,分,秒
        from (select to_number(to_char(FromDate,'SSSSS')) as FromS,
                     to_number(to_char(ToDate  ,'SSSSS')) as ToS
              from dual);

        DBMS_Output.Put_Line(to_char(FromDate,'YYYY/MM/DD HH24:MI:SS') || 'から'
         || to_char(ToDate  ,'YYYY/MM/DD HH24:MI:SS') || 'は'
         || LPad(日,2) || '日と' || LPad(時間,2) || '時間'
         || LPad(分,2,'0') || '分' ||  LPad(秒,2,'0') || '秒');
    end Loop;
end;
/


解説

to_char関数でSSSSSを指定して、秒を求めてます。

7-25 経過時間を取得(低精度)

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
2008/9/24 追記
秒への変換において誤差は発生しないようなので(分母をはらえるからだと思いますが)、
単純に秒の差を求めてから演算したほうがシンプルでしょうねぇ

select
trunc(secdef/24/60/60) as 日,
trunc(mod(secdef,24*60*60)/60/60) as 時間,
trunc(mod(secdef,60*60)/60) as 分,
mod(secdef,60) as 秒
from (select
      (to_date('2005/08/05 05:00:00','yyyy/mm/dd hh24:mi:ss')
      -to_date('2005/08/01 23:00:50','yyyy/mm/dd hh24:mi:ss')) *24*60*60 as secdef
      from dual);

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
ストアドファンクションにしとくといいかもしれません。

create or replace function jikansa(FromDate date,ToDate date) return varchar2 is
    日   varchar2(2);
    時間 varchar2(2);
    分   varchar2(2);
    秒   varchar2(2);

    FromS pls_Integer;
    ToS pls_Integer;
begin
    FromS := to_number(to_char(FromDate,'SSSSS'));
    ToS   := to_number(to_char(ToDate  ,'SSSSS'));

    日   := extract(day from NumToDsInterval(ToDate-FromDate,'day'));
    時間 := case when FromS < ToS then trunc((ToS-FromS)/3600)
                 when FromS > ToS then trunc((24*60*60-FromS+ToS)/3600)
                 else 0 end;
    分   := case when FromS < ToS then trunc(mod(ToS-FromS,3600)/60)
                 when FromS > ToS then trunc(mod(24*60*60-FromS+ToS,3600)/60)
                 else 0 end;
    秒   := case when FromS < ToS then mod(ToS-FromS,60)
                 when FromS > ToS then mod(24*60*60-FromS+ToS,60)
                 else 0 end;
    return (to_char(FromDate,'YYYY/MM/DD HH24:MI:SS') || 'から'
         || to_char(ToDate  ,'YYYY/MM/DD HH24:MI:SS') || 'は'
         || LPad(日,2) || '日と' || LPad(時間,2) || '時間'
         || LPad(分,2,'0') || '分' ||  LPad(秒,2,'0') || '秒');
end;
/


select
jikansa(to_date('2008/10/10 16:10:10','yyyy/mm/dd hh24:mi:ss'),
        to_date('2008/10/10 23:10:10','yyyy/mm/dd hh24:mi:ss')) as sa1,
jikansa(to_date('2008/10/10 22:15:30','yyyy/mm/dd hh24:mi:ss'),
        to_date('2008/10/10 01:10:10','yyyy/mm/dd hh24:mi:ss')) as sa2
  from dual;

2008/10/10 16:10:10から2008/10/10 23:10:10は 0日と 7時間00分00秒
2008/10/10 22:15:30から2008/10/10 01:10:10は 0日と 2時間54分40秒