我有一个要求,当我们提供两个日期作为输入时,以下列格式输出:
sysdate
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秒"
它可以是查询或函数
答案 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_CHAR
对INTERVAL
数据类型无法正常工作,输出格式是修复的。因此,你可以做正则表达,例如
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;