トップページに戻る
次の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秒