【问题标题】:Human readable elapsed time between many days许多天之间的人类可读的经过时间
【发布时间】:2017-10-27 08:35:40
【问题描述】:

我使用 Oracle SQL,我有一个包含 3 列的表:ProcessStart DateEnd Date。我想计算每个过程的持续时间。

我使用了这个查询:

select 
(enddate.date_value - startdate.date_value) as duration
from dual

结果以天为单位。

例如:开始日期为30.3.2016 17:14:53,结束日期为8.7.2016 14:51:21

当我使用查询时,结果是99.90032407407407407407407407407407407407,但我想要这样的结果: 3 months, 7 days, 21 hours, 36 minutes, 28 seconds.

我该怎么做?

【问题讨论】:

  • 一旦你想要大于天的单位,你就会遇到问题。您必须选择是否要撒谎并有标准长度的月份(例如全部 30 天),或者您的情况是“3 个月、7 天……”可以代表不同的实际时间段,具体取决于何时 期间发生的年份。两者都不是特别吸引人。你确定你真的需要你在这里要求的东西,并且那些要求它的人理解这些权衡吗?
  • @Damien_The_Unbeliever,我同意你的看法,如果你只想转换几天,但如果你想在两个日期之间有一个持续时间表示,你不需要每月固定的天数(例如全部 30 天)或每年固定的天数,看看我的建议(我相信我们可以简化/优化它,但它似乎可行!)
  • @Indent - 我试图表明的是,如果您不采用固定长度的月份,“3 个月、7 天……”可能代表不同的时间段。 IE。它是 2000 年 2 月 1 日至 5 月 8 日之间的时间段,实际时间段为 97 天。在这些相同日期之间的一年后,它代表 96 天。在 OP 示例中,它代表 99 天。
  • like this momentjs.com/docs/#/plugins/preciserange 阅读我的答案 我从来没有在我的查询中采用固定的月份数,但我找到了预期的结果。在 OPs 示例中,它表示 30.3.2016 17:14:53 和 8.7.2016 14:51:21 之间的持续时间
  • 我用moment.js 例子添加了测试,我的代码产生了同样的结果。

标签: sql oracle


【解决方案1】:

这个复杂的查询(专门针对 DAY !!):

为了计算出正确的 Day,我将 Month 和 12 * Year 添加到原始日期。

with dates as(
select
   sysdate       as d1,
   sysdate-99.90032407407407407407407407407407407407-365  as d2
from
   dual
),
dates_parts as (
SELECT
    d1,
    d2,
    EXTRACT(YEAR   FROM (d1 - d2) YEAR TO MONTH ) as Year,
    EXTRACT(MONTH  FROM (d1 - d2) YEAR TO MONTH ) as Month,
    EXTRACT(DAY    FROM (d1 - d2) DAY TO SECOND ) as Day,
    EXTRACT(HOUR   FROM cast(d1 as timestamp) - cast(d2 as timestamp)) as Hour,
    EXTRACT(MINUTE FROM cast(d1 as timestamp) - cast(d2 as timestamp)) as Minute,    
    EXTRACT(SECOND FROM cast(d1 as timestamp) - cast(d2 as timestamp)) as Second
FROM dates
)
select
    dates_parts.Year,
    dates_parts.Month,
    dates_parts.Day,
    dates_parts.Hour,
    dates_parts.Minute,
    dates_parts.Second,
    EXTRACT(DAY FROM (d1 - ADD_MONTHS(d2,Month+Year*12)) DAY TO SECOND ) as Day_Corrected
from 
    dates_parts

将产生不同的日期部分:

| YEAR | MONTH | DAY | HOUR | MINUTE | SECOND | DAY_CORRECTED |
|------|-------|-----|------|--------|--------|---------------|
|    1 |     3 | 464 |   21 |     36 |     28 |             7 |

【讨论】:

    【解决方案2】:

    两个DATE 值之间的差异是一个number,代表天数。你似乎想要一个interval,这可以使用TIMESTAMP 值来完成。

    select cast(enddate as timestamp) - cast(startdate as timestamp)
    from the_table
    

    subtracting a timestamp from a timestamp 的结果是一个区间。

    然而,

    格式化 interval 值在 Oracle 中相当棘手。参见例如format interval with to_char

    【讨论】:

    • 其实只投一个就足够了,enddate或者startdate
    【解决方案3】:

    根据我之前的回答,您可以创建一个 Oracle 函数sinceHumanReadable

    https://momentjs.com/docs/#/plugins/preciserange/ 的示例产生相同的结果

    moment("2014-01-01 12:00:00").preciseDiff("2015-03-04 16:05:06");
    // 1 year 2 months 3 days 4 hours 5 minutes 6 seconds
    

    http://sqlfiddle.com/#!4/d6783/1

    create or replace FUNCTION sinceHumanReadable(start_date IN date,end_date IN date) 
        RETURN VARCHAR2
    IS result VARCHAR2(255);
    
        BEGIN 
    
        with 
        dates_parts as (
        SELECT
            EXTRACT(YEAR   FROM (end_date - start_date) YEAR TO MONTH ) as Year,
            EXTRACT(MONTH  FROM (end_date - start_date) YEAR TO MONTH ) as Month,       
            EXTRACT(HOUR   FROM cast(end_date as timestamp) - cast(start_date as timestamp)) as Hour,
            EXTRACT(MINUTE FROM cast(end_date as timestamp) - cast(start_date as timestamp)) as Minute,    
            EXTRACT(SECOND FROM cast(end_date as timestamp) - cast(start_date as timestamp)) as Second
        FROM dual
        ),
        dates_parts_with_day as (
        select        
            Year,Month,Hour,Minute,Second,
            EXTRACT(DAY FROM (end_date - ADD_MONTHS(start_date,Month+Year*12)) DAY TO SECOND ) as Day
        from dates_parts
        )
        select
            decode(dates_parts_with_day.Year, 0,'', dates_parts_with_day.Year  || ' years ' )||
            decode(dates_parts_with_day.Month,0,'', dates_parts_with_day.Month || ' months ')||
            decode(dates_parts_with_day.Day,0,'', dates_parts_with_day.Day || ' days ')||
            decode(dates_parts_with_day.Hour,0,'', dates_parts_with_day.Hour || ' hours ')||
            decode(dates_parts_with_day.Minute,0,'', dates_parts_with_day.Minute || ' minutes ')||
            dates_parts_with_day.Second || ' seconds'
        into result
        from 
            dates_parts_with_day;
    
        RETURN(result); 
    
        END sinceHumanReadable;
    GO
    

    查询

    with dates as (    
      select sysdate-99.90032407407407407407407407407407407407 as d1,sysdate  as d2 from dual
      union all
      select to_date('2016-03-30 17:14:53','yyyy-mm-dd hh24:mi:ss') as d1,to_date('2016-07-08 14:51:21','yyyy-mm-dd hh24:mi:ss')   as d2 from dual
      union all
      select to_date('2014-01-01 12:00:00','yyyy-mm-dd hh24:mi:ss') as d1,to_date('2015-03-04 16:05:06','yyyy-mm-dd hh24:mi:ss')   as d2 from dual  
      union all
      select sysdate as d1,add_months(sysdate,35)   as d2 from dual
      union all
      select sysdate as d1,sysdate as d2 from dual
    )
    select
        d1,d2,
        sinceHumanReadable(d1,d2) as since
    from
        dates;
    

    将产生:

    |                   D1 |                   D2 |                                               SINCE |
    |----------------------|----------------------|-----------------------------------------------------|
    | 2017-07-19T17:50:00Z | 2017-10-27T15:26:28Z |      3 months 7 days 21 hours 36 minutes 28 seconds |
    | 2016-03-30T17:14:53Z | 2016-07-08T14:51:21Z |      3 months 7 days 21 hours 36 minutes 28 seconds |
    | 2014-01-01T12:00:00Z | 2015-03-04T16:05:06Z | 1 years 2 months 3 days 4 hours 5 minutes 6 seconds |
    | 2017-10-27T15:26:28Z | 2020-09-27T15:26:28Z |                         2 years 11 months 0 seconds |
    | 2017-10-27T15:26:28Z | 2017-10-27T15:26:28Z |                                           0 seconds |
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-10
      • 2011-07-21
      • 2016-07-05
      • 2017-09-04
      • 1970-01-01
      • 2015-04-06
      • 2011-05-26
      • 2012-07-16
      相关资源
      最近更新 更多