格式化日期(差异) - Oracle

时间:2014-10-21 07:44:23

标签: sql oracle

我有一个要求,当我们提供两个日期作为输入时,以下列格式输出:

  • 输入1 - > sysdate
  • 输入2 - > to_date('10-OCT-2014') - >这是动态的

输出:

11 days 00 Hours 27 Minutes 41 Seconds

秒可以是可选的。 目前正在使用

select  TRIM (TRAILING '.' FROM (TRIM (BOTH '0' FROM (TRIM (LEADING '+' FROM NUMTODSINTERVAL (
                                                                                                (24
                                                                                                 * 60
                                                                                                 * 60
                                                                                                 * (SYSDATE   -                                                                                                
                                                                                                       to_date('10-OCT-2014'))),
                                                                                                'second')))))) from dual

但输出将类似于" 11 00:27:41"但要求是" 11天00小时27分钟41秒"

它可以是查询或函数

3 个答案:

答案 0 :(得分:3)

select extract(day from ds_int) || ' days ' 
    || extract(hour from ds_int) || ' Hours '  
    || extract(minute from ds_int) || ' Minutes '  
    || extract(second from ds_int) || ' Second'  
from
(select numtodsinterval(sysdate - to_date('10-10-2014', 'DD-MM-YYYY'), 'day') ds_int from dual);

尾随“0”(不适用于负间隔)

select extract(day from ds_int) || ' days ' 
    || lpad(extract(hour from ds_int), 2, 0) || ' Hours '  
    || lpad(extract(minute from ds_int), 2, 0) || ' Minutes '  
    || lpad(extract(second from ds_int), 2, 0) || ' Second'  
from
(select numtodsinterval(sysdate - to_date('10-10-2014', 'DD-MM-YYYY'), 'day') ds_int from dual);

但是有一个限制 - 一天可能包含9位数(最多)

最好避免使用诸如“to_date('10 -OCT-2014')”之类的构造“ - 结果可能无法预测(取决于会话的NLS设置)。更好地定义一个掩码“to_date('10 -10-2014','DD-MM-YYYY')”

答案 1 :(得分:0)

当您希望使用TIMESTAMP值时,最好使用DATE而不是INTERVAL数据类型。但是,NUMTODSINTERVAL也应该没问题。

TO_CHARINTERVAL数据类型无法正常工作,输出格式是修复的。因此,你可以做正则表达,例如

SELECT 
regexp_replace(systimestamp - timestamp '2014-10-10 00:00:00', 
   '.?0*(\d+) (\d{2}):(\d{2}):(\d{2}).*', 
   '\1 days \2 hours \3 minutes \4 seconds') from dual;

或者您更喜欢NUMTODSINTERVAL:

SELECT 
REGEXP_REPLACE(NUMTODSINTERVAL(24*60*60* (SYSDATE-TO_DATE('10-OCT-2014')), 'SECOND'), 
    '.?0*(\d+) (\d{2}):(\d{2}):(\d{2}).*', 
    '\1 days \2 hours \3 minutes \4 seconds') 
FROM dual;
仅当您的间隔始终为正时,

EXTRACT (datetime)才适用,否则您会在每个组件中获得-

答案 2 :(得分:0)

我总是很感激与SQL日期时间格式相关的问题。世界上有这么多愚蠢的黑客攻击(例如转换为字符串并进行字符串操作)....

由于您的问题是oracle特定的,因此应接受Multisync的答案。但是,如果有人寻找不需要numtodsinterval函数的版本(为了便携性或其他东西),你也可以尝试这个更详细的解决方案:

with base as (
    select abs(sysdate-to_date('2014-10-10', 'YYYY-MM-DD')) as diff
    from dual
), days as (
    select floor(diff) part,
           diff-floor(diff) remainder
    from base
), hours as (
    select floor(remainder*24) part,
           remainder*24-floor(remainder*24) remainder
   from days
), minutes as (
    select floor(remainder*60) part,
           remainder*60-floor(remainder*60) remainder
    from hours
), seconds as (
    select floor(remainder*60) part
    from minutes
)
select days.part||' days '||
       lpad(hours.part, 2, '0')||' hours '||
       lpad(minutes.part, 2, '0')||' minutes '||
       lpad(seconds.part, 2, '0')||' seconds'
from days, hours, minutes, seconds;

尊重差异方向的扩展解决方案

with base as (
    select sysdate now, to_date('2014-10-10', 'YYYY-MM-DD') otherdate
    from dual
), diff as (
    select abs(now-otherdate) as value,
           sign(now-otherdate) as dir
    from base
), days as (
    select floor(value) part,
           value-floor(value) remainder
    from diff
), hours as (
    select floor(remainder*24) part,
           remainder*24-floor(remainder*24) remainder
   from days
), minutes as (
    select floor(remainder*60) part,
           remainder*60-floor(remainder*60) remainder
    from hours
), seconds as (
    select floor(remainder*60) part
    from minutes
)
select case dir
    when 1 then 'before '||strbuilder.intervalstr
    when -1 then 'after '||strbuilder.intervalstr
    else 'now' end
from (
    select days.part||' days '||
           lpad(hours.part, 2, '0')||' hours '||
           lpad(minutes.part, 2, '0')||' minutes '||
           lpad(seconds.part, 2, '0')||' seconds ' as intervalstr
    from days, hours, minutes, seconds
) strbuilder, diff;