2. 컴퓨터 이야기/데이타베이스

오라클 Date 데이타들 간의 경과(시간차)를 일/분/초로 확인하는 방법

래빗 크리스 2010. 1. 20. 17:31


오라클에서 Date 형으로 된 시간들의 차이를 구할때, to_char 함수를 이용하여 문자열로 변환한 다음..
각각의 자리에 시간과 분과 초에 해당하는 값들을 일일이 대입하고 각각 연산하는 경우를 보았는데..
대략 난감하다.

실제로 오라클은 months_between 함수를 통해 두 시점간의 개월수를 구하는 함수와
trunc 와 round 함수를 통해 두 시점간의 일자수를 구하는 함수 등은 지원한다.
그리고 round 의 경우 사사오입되면 오차가 발생하므로 정확히 일자를 구분한다면 trunc 를 사용한다.

여기서 우리가 알고 싶은 것은..
두 시점간의 시간, 분, 초를 구하는 방법이다.
기본 함수가 없기 때문에 산식으로 구현해야 한다.

미리 알아 두어야 할 것은.. 오라클은 일자를 정수의 증감으로 보고,
정수를 24 로 나누면 시간, 시간을 60 으로 나누면 분, 분을 60 으로 나누면 초가 되도록 date 를 구현한다는 것.

아래와 같이 2010 년 1월 20일 17:00:00 와 동일년도 동일월 동일일자 16:59:58 와의 시차를 구해 봤다.
쿼리를 짧게 구성할 수도 있지만, 이해를 돕기 위해서 day / hour / min / sec 순으로 코딩했다.
select a.*,
          trunc((a-day/1-hour/24-min/24/60)*24*60*60) sec
  from (select a.*, trunc((a-day-hour/24)*24*60) min
          from (select a.*, trunc((a-day)*24) hour
                  from (select a.*, trunc(a) day
                          from (select to_date('20100120 17:00:00','yyyymmdd hh24:mi:ss')-
                                       to_date('20100120 16:59:58','yyyymmdd hh24:mi:ss') a
                                  from dual) a
                       ) a
               ) a
       ) a
;

일자를 계산할때 통상 trunc 를 사용하여 왔기 때문에 상기 쿼리에도 trunc 를 사용하였다.
그런데, 혹시 시차가 변경될때 미묘한 변화는 없는 것일까..?
이것을 알아 보기 위해 trunc 함수 외에 ceil 과 round 를 비교해 보았다.
아래와 같이 함수들을 이용하여 sec1, sec2, sec3 를 구해 보았다.
모두 '2' 가 나왔다. 그러면 두 시점의 다른 값은 그대로 두고 일자만 변경하면 어떻게 될까..?
select a.*,
       trunc((a-day/1-hour/24-min/24/60)*24*60*60) sec1,
       ceil((a-day/1-hour/24-min/24/60)*24*60*60) sec2,
       round((a-day/1-hour/24-min/24/60)*24*60*60) sec3
  from (select a.*, trunc((a-day-hour/24)*24*60) min
          from (select a.*, trunc((a-day)*24) hour
                  from (select a.*, trunc(a) day
                          from (select to_date('20100120 17:00:00','yyyymmdd hh24:mi:ss')-
                                       to_date('20100120 16:59:58','yyyymmdd hh24:mi:ss') a
                                  from dual) a
                       ) a
               ) a
       ) a
;

아래와 같이 코드를 만들어 보니 ceil 함수는 값이 이상하게 나왔다.
trunc 나 round 함수는 2 가 나왔는데 3 이 나오는 것이다.
select a.*,
       trunc((a-day/1-hour/24-min/24/60)*24*60*60) sec1,
       ceil((a-day/1-hour/24-min/24/60)*24*60*60) sec2,
       round((a-day/1-hour/24-min/24/60)*24*60*60) sec3
  from (select a.*, trunc((a-day-hour/24)*24*60) min
          from (select a.*, trunc((a-day)*24) hour
                  from (select a.*, trunc(a) day
                          from (select to_date('20100121 17:00:00','yyyymmdd hh24:mi:ss')-
                                       to_date('20100120 16:59:58','yyyymmdd hh24:mi:ss') a
                                  from dual) a
                       ) a
               ) a
       ) a
;

일자간격은 그대로 두고 분의 간격을 하나 더 늘려 보니 이제는 trunc 쪽 값이 다르게 나왓다.
select a.*,
       trunc((a-day/1-hour/24-min/24/60)*24*60*60) sec1,
       ceil((a-day/1-hour/24-min/24/60)*24*60*60) sec2,
       round((a-day/1-hour/24-min/24/60)*24*60*60) sec3
  from (select a.*, trunc((a-day-hour/24)*24*60) min
          from (select a.*, trunc((a-day)*24) hour
                  from (select a.*, trunc(a) day
                          from (select to_date('20100122 17:01:00','yyyymmdd hh24:mi:ss')-
                                       to_date('20100120 16:59:58','yyyymmdd hh24:mi:ss') a
                                  from dual) a
                       ) a
               ) a
       ) a
;

그렇다는 얘기는 round 도 언젠가는 값이 틀려질 수 있다는 얘기가 아닐까..?
이 부분은 이 글을 읽는 분들의 판단에 맡기겠다.
필자의 경우에는 round 로 두 시점간의 초를 체크하는 것이 틀린 적은 없는 것같다.
아마도, 초를 구분해 주는 값의 차이는 극히 미량이기 때문에 그런 것은 아닐까 추측해 볼뿐이다.
이것에 대해 학문적으로 연구된 것이 있거나 명쾌한 답을 아는 분이 계시면 댓글을 바라는 마음 간절하다..

아, 시간이나 분에 대해서도 trunc, ceil, round 함수를 비교해 보았다.
시간과 분의 경우에는 ceil 일 때에만 문제가 있고 trunc 나 round 에서는 정상 작동하였다.
그래서 시간 함수에서는 대체로 trunc 를 사용해 왔기 때문에..
시간과 분의 시차에는 trunc 를 사용하고, 초의 시차에 대해서는 round 를 사용하면 될 것으로 보인다.