суббота, 27 ноября 2010 г.

Get a difference between dates (получить разницу между датами)

Распространенный вопрос, при вычитании получается число, и что с ним делать дальше часто никто не знает, либо начинают сочинять невероятные решения.

После появления в Oracle интервальных типов:
  • INTERVAL YEAR TO MONTH
  • INTERVAL DAY TO SECOND
жить стало проще и разницу дат можно представить в виде интервала INTERVAL DAY TO SECOND (в днях/часах/минутах/секундах/милисекундах), используя следующие функции:

Формат NUMTODSINTERVAL(n, 'interval_unit'):
  • NUMTODSINTERVAL(5, 'DAY')
  • NUMTODSINTERVAL(21, 'HOUR')
  • NUMTODSINTERVAL(10, 'MINUTE')
  • NUMTODSINTERVAL(15, 'SECOND')

Формат TO_DSINTERVAL('D HH:MI:SS'):
  • TO_DSINTERVAL('5 21:10:15')

Примеры:

alter session set nls_date_format = 'DD.MM.YYYY HH24:MI:SS';

set linesize 256

COLUMN DSINTERVAL2 FORMAT A20
COLUMN DSINTERVAL3 FORMAT A20

with dates as (
  select to_date('20.11.2010 23:10:05', 'DD.MM.YYYY HH24:MI:SS') date_begin,
         to_date('26.11.2010 20:20:20', 'DD.MM.YYYY HH24:MI:SS') date_end
    from dual
)
select d.*,
       --Разница дат в до появления интервальных типов
       date_end - date_begin date_diffirence,
       --Приведение к интервальному типу при помощи NUMTODSINTERVAL
       NUMTODSINTERVAL(date_end - date_begin, 'DAY') DSINTERVAL2,
       --Приведение к интервальному типу при помощи day(5) to second(0)
       (date_end - date_begin) day(5) to second(0) DSINTERVAL3,
       -- Интервал в строковом виде заданного формата
       to_char(extract(day from (date_end - date_begin) day(5) to second(0)), '99') || 'd' ||
       to_char(extract(hour from (date_end - date_begin) day(5) to second(0)), '99') || 'h' ||
       to_char(extract(minute from (date_end - date_begin) day(5) to second(0)), '99') || 'm' ||
       to_char(extract(second from (date_end - date_begin) day(5) to second(0)), '99') || 's' as DSNTERVAL_TO_STR4,
       --Вычитаем из даты интервал
       date_end - TO_DSINTERVAL('5 21:10:15') DATE_BEGIN2,
       --Прибавляем к дате интервал
       date_begin + TO_DSINTERVAL('5 21:10:15') DATE_END2
  from dates d
 where 1 = 1
   and ( 
         numtodsinterval(date_end - date_begin, 'DAY') between numtodsinterval(-10, 'DAY') and numtodsinterval(10, 'DAY')
         or
         (date_end - date_begin) day(5) to second(0) between numtodsinterval(-10, 'DAY') and numtodsinterval(10, 'DAY')
         or
         (date_end - date_begin) day(5) to second(0) between to_dsinterval('-10 00:00:00') and to_dsinterval('10 00:00:00')
       )
;

DATE_BEGIN            DATE_END              DATE_DIFFIRENCE DSINTERVAL2                                        DSINTERVAL3                                        DSNTERVAL_TO_STR4 DATE_BEGIN2           DATE_END2            
--------------------- --------------------- --------------- -------------------------------------------------- -------------------------------------------------- ----------------- --------------------- ---------------------
11/20/2010 23:10:05   11/26/2010 20:20:20        5.88211806 +05 21:10:15.000000                                +05 21:10:15.000000                                  5d 21h 10m 15s  11/20/2010 23:10:05   11/26/2010 20:20:20  
1 row selected.

Комментариев нет:

Отправить комментарий