如何在oracle中减去2个日期以获得小时和分钟的结果

Posted

技术标签:

【中文标题】如何在oracle中减去2个日期以获得小时和分钟的结果【英文标题】:How to subtract 2 dates in oracle to get the result in hour and minute 【发布时间】:2011-11-19 14:09:24 【问题描述】:

我想减去 2 个日期并将结果以小时和分钟表示为一位小数。

我有下表,我正在这样做,但结果不理想。

有一些细微的变化,我确信这是简单的算术,但我没有做对。

select start_time, end_time, (end_time-start_time)*24 from 
come_leav;    
START_TIME END_TIME (END_TIME-START_TIME)*24 ------------------- -------- ------------ ------------ 21-06-2011 14:00:00 21-06-2011 16:55:00 2.9166667 21-06-2011 07:00:00 21-06-2011 16:50:00 9.8333333 21-06-2011 07:20:00 21-06-2011 16:30:00 9.1666667

我想要的结果(end_time-start_time)如下。

16:55- 14:00 = 2.55 16:50-07:00 = 9.5 16:30-7:20 = 9.1 以此类推。

我该怎么做?

【问题讨论】:

预期结果看起来相当荒谬。应该是这样的。 16:55- 14:00 = 2:55 或 2.92 16:50-07:00 = 9:50 或 9.83 16:30-7:20 = 9:10 或 9.17 我能否以 2.55 的形式获得它。我实际上是在报告时间和超时并计算小时和分钟的差异。谢谢。 我不得不说,这可能是我在 Stack Overflow 上看到的写得最好的 SQL 问题之一。我知道你可能早就忘记了这一点,但我不得不说。 【参考方案1】:

试试这个:

    SELECT
    TRIM(TO_CHAR(TRUNC(((86400*(end_time - start_time))/60)/60)-24*(trunc((((86400*(end_time - start_time))/60)/60)/24)),'00')) ||'.'||
    TRIM(TO_CHAR(TRUNC((86400*(end_time - start_time))/60)-60*(trunc(((86400*(end_time - start_time))/60)/60)),'00')) ||'.'  as duration
FROM come_leav;

【讨论】:

感谢您的帮助,我得到了想要的结果,但如果没有连接我就无法得到它,我的意思是作为最终结果,因为我必须使用它来计算时间和超时的差异。 @Macky 如果您必须使用它来计算东西,那么您原始帖子中的结果是正确的。 1h30 是一小时半,半是 0.5,所以 1h30 = 1.5 小时。 嗨 roslan,你是对的,但我希望按照我的要求完成计算,因为我想找到开始时间和结束时间之间的时间差。所以我希望之前要求的结果,即 16:55-14:00 为 2.55 而不是 2.916667。所以请建议一种更简单的方法谢谢... @Macky,我已经编辑了帖子...用 . 替换了 : 分隔符。并从字符串中删除秒数。【参考方案2】:

试试这个

round(to_number(end_time - start_time) * 24)

【讨论】:

感谢您的帮助。但结果不是我想要的。见下文 SQL> select to_number(end_time-start_time)*24 from come_leav; TO_NUMBER(END_TIME-START_TIME)*24 --------------------------------- 2.9166667 9.8333333 9.1666667 9.1666667 9.1666667 7.1666667 我没有安装 oracle 数据库,因此无法检查我给出的查询。抱歉,答案不正确/不完整。 在某种意义上它是准确的,因为它给出了分钟的十进制等值 - 只需将该部分乘以 60。问题是 OP 需要它作为 HH.MM 的奇怪要求。跨度> FLOOR((end_time - start_time) * 24) || '.' || ROUND(((end_time - start_time) * 24) - FLOOR((end_time - start_time) * 24)*60) 可能是 OP 需要使用它的方式。【参考方案3】:

Oracle 将日期表示为天数,因此(end_time-start_time)*24 为您提供小时数。假设您在h 列中有这个数字(例如2.9166667)。然后您可以轻松地将其转换为您想要的格式:FLOOR(h) + (h-FLOOR(h))/100*60

例子:

WITH diff AS (
    SELECT (TO_DATE('21-06-2011 16:55:00', 'DD-MM-YYYY HH24:MI:SS') - TO_DATE('21-06-2011 14:00:00', 'DD-MM-YYYY HH24:MI:SS'))*24 h
    FROM dual
) SELECT FLOOR(h) + (h-FLOOR(h))/100*60
FROM diff

在你的情况下:

SELECT start_time, end_time,
    FLOOR((end_time-start_time)*24) + ((end_time-start_time)*24-FLOOR((end_time-start_time)*24))/100*60 AS hours_diff
FROM come_leav 

【讨论】:

【参考方案4】:

您可以使用提取物:

SELECT start_time, end_time, extract(HOUR FROM end_time-start_time) || '.' || extract(MINUTE FROM end_time-start_time)  
From come_leav;

【讨论】:

我收到以下错误:SQL> SELECT start_time, end_time, extract(HOUR FROM end_time-start_time) || '。' ||提取(MINUTE FROM end_time-start_time)来自come_leav;选择 start_time、end_time、extract(HOUR FROM end_time-start_time) || '。' || extract(MINUTE FROM end_time-start_time) From come_leav * ERROR at line 1: ORA-30076: invalid extract field for extract source @roselan 我得到与 Macky 相同的错误。如果它起作用会很棒,或者可以让它起作用。【参考方案5】:
SQL> edit
Wrote file afiedt.buf

  1  select start_date
  2      , end_date
  3      , (24 * extract(day from (end_date - start_date) day(9) to second))
  4          + extract(hour from (end_date - start_date) day(9) to second)
  5          + ((1/100) * extract(minute from (end_date - start_date) day(9) to second)) as "HOUR.MINUTE"
  6* from t
SQL> /

START_DATE          END_DATE            HOUR.MINUTE
------------------- ------------------- -----------
21-06-2011 14:00:00 21-06-2011 16:55:00        2.55
21-06-2011 07:00:00 21-06-2011 16:50:00         9.5
21-06-2011 07:20:00 21-06-2011 16:30:00         9.1

遇到此代码的人应注意,小数部分是实际的分钟差异,而不是一小时的一部分。因此,.5 代表 50 minutes,而不是 30 minutes

【讨论】:

下面是我运行它时的结果。但是请看一下最后一行,它给了我 7.1,因为我需要它是 7.5(14-6.50),而不会危及其他数字。感谢您的帮助 START_TIME END_TIME HOUR.MINUTE -------------------- -------------------- ---- 21-06-2011 14:00:00 21-06-2011 16:55:00 2.55 21-06-2011 07:00:00 21-06-2011 16:50:00 9.5 21-06-2011 07:20 :00 21-06-2011 16:30:00 9.1 22-06-2011 07:20:00 22-06-2011 16:30:00 9.1 23-06-2011 07:20:00 23-06-2011 16 :30:00 9.1 21-06-2011 06:50:00 21-06-2011 14:00:00 7.1 @Macky。这是没有意义的。您要求减去将导致hours.minutes 的时间。 (开始时没有多大意义。) 14:00 减去 6:50 等于 7 小时 10 分钟或 7.1。您是说希望 2:00 - 1:59 为 0.41 持续一分钟,1:41 - 1:00 为 0.41 持续 41 分钟? @ShannonSeverance 很好地破译了他想要的东西和上面的代码。作为帖子中代码的注释,由于 OP 的奇数要求,应该注意小数点描述的是实际分钟,而不是一小时的小数部分。我提交了修改。【参考方案6】:

编辑:如果你需要一个数字,那么

    trunc(end_date-start_date)*24+
    to_number(to_char(trunc(sysdate)+(end_date-start_date),'HH24.MI'))

对于字符串结果,如果 delta 小于 24H: 我会去的

    to_char(trunc(sysdate)+(end_date-start_date),'HH24.MI')

...'HH24:MI:SS',但这是我个人的喜好。

对于超过 24 小时的术语,我会以

为前缀
    trunc(end_date-start_date)||"days "||
    to_char(trunc(sysdate)+(end_date-start_date),'HH24.MI')

是的,因为 oracle 以天为单位,以秒为精度,您正在处理算术问题。一次是因为您只处理分钟数(因此您可能会将您的数字四舍五入为trunc(days*24*60+0.5)/24/60),但数字 1/24/60 上的二进制算术不精确可能仍然会给您带来麻烦。

Edit2.1:

    to_char(24*(trunc(end_date)-trunc(start_date))+to_number(to_char(end_date,'HH24.MI'))-to_number(to_char(start_date,'HH24.MI')),'99999.99')

但是对于平均值,结果可能相当混乱,因为小数点 7.50 表示 7 个半小时,或至少 7 小时 50 分钟,而不是 7 小时 10 分钟的经过时间。

【讨论】:

从 come_leav 中选择 start_time, end_time, to_char(trunc(sysdate)+(end_time-start_time),'HH24.MI'); S_TIME E_TIME T_C 21-06-2011 14:00:00 21-06-2011 16:55:00 02.55 21-06-2011 07:00:00 21-06-2011 16:50:00 09.50 21-06-2011 07:20:00 21-06-2011 16:30:00 09.10 22-06-2011 07:20:00 22-06-2011 16:30:00 09.10 23-06-2011 07:20:00 23-06 -2011 16:30:00 09.10 21-06-2011 06:50:00 21-06-2011 14:00:00 07.10。请查看最后一个结果 (14-06.50) 返回 07.10,我希望它为 (14-06.50) = 7.5。有什么建议可以克服这个问题。感谢您的帮助。 这就是我得到的,似乎已经修复了最后一个,但请看一下它给出的第一个 -88.45 而不是 2.55。请帮助我做对。欣赏.. START_TIME END_TIME --------- -------------------- TRUNC(END_TIME-START_TIME)+TO_CHAR(TO_NUMBER(TO_CHAR(END_TIME,'HH24 .MI'))-TO_NUMBER(TO_CHAR(START_TI ---------------------------------------- ----------------------------- 21-09-2011 14:00:00 21-06-2011 16:55:00 - 88.45 21-06-2011 07:00:00 21-06-2011 16:50:00 9.5 23-06-2011 07:20:00 23-06-2011 16:30:00 9.1 21-06-2011 06: 50:00 21-06-2011 14:00:00 7.5 好吧,犯了一些错误,2.1 现在可以按您的意愿运行了。但是因为它们在不同的月份不能得到 2.55,并且 end 小于 start,所以必须导致一个很大的负数。 (如果你删除 24*(...)+ 部分,你会得到 2.55,但你不应该) 嗨@vmatyi,对不起。是的,那个日期在不同的月份。它必须在同一个月,否则我应该说它将在同一天。我通过从 time_in 中减去 time_out 来获得 hr.min 来找到差异。这是从时钟机器获取的数据,该机器跟踪员工进出时间并报告总小时数和迟到时间。我正在这样做。 return(trunc(:et_time-:st_time)+to_char(to_number(to_char(:et_time, 'HH24.MI'))-to_number(to_char(:st_time,'HH24.MI')),'9.99')); 【参考方案7】:

这个查询对我来说非常有用,如果有人想要 start_date 和 end_date 之间的时间差异,比如 HH:MI:SS,请使用这个查询。

SELECT
    TRIM(TO_CHAR(TRUNC(((86400*(end_date - start_date))/60)/60)-24*(trunc((((86400(end_date - start_date))/60)/60)/24)),'00')) ||'.'||
    TRIM(TO_CHAR(TRUNC((86400*(actual_completion_date - actual_start_date))/60)-60*(trunc(((86400*(end_date - start_date))/60)/60)),'00')) ||'.'||
    TRIM(TO_CHAR(TRUNC((86400*(end_date - start_date)))-60*(trunc((86400*(end_date - actual_start_date))/60)),'00')) as duration  
FROM fnd_concurrent_requests; 

【讨论】:

【参考方案8】:

这是一种非常难看的方法,第一部分并没有完全受到 OP 的质疑,但它提供了一种通过减去 2 个日期字段来获得结果的方法——在我的例子中,CREATED_DATE 和今天由SYSDATE代表:

SELECT FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE)) / 12) || ' years, '  
|| (FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE))) - 
   (FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE)) / 12)) * 12) || ' months, '  
-- we take total days - years(as days) - months(as days) to get remaining days
|| FLOOR((SYSDATE - CREATED_DATE) -      -- total days
   (FLOOR((SYSDATE - CREATED_DATE)/365)*12)*(365/12) -      -- years, as days
   -- this is total months - years (as months), to get number of months, 
   -- then multiplied by 30.416667 to get months as days (and remove it from total days)
   FLOOR(FLOOR(((SYSDATE - CREATED_DATE)/365)*12 - (FLOOR((SYSDATE - CREATED_DATE)/365)*12)) * (365/12)))  
|| ' days, '   
-- Here, we can just get the remainder decimal from total days minus 
-- floored total days and multiply by 24       
|| FLOOR(
     ((SYSDATE - CREATED_DATE)-(FLOOR(SYSDATE - CREATED_DATE)))*24
   )
|| ' hours, ' 
-- Minutes just use the unfloored hours equation minus floored hours, 
-- then multiply by 60
|| ROUND(
       (
         (
           ((SYSDATE - CREATED_DATE)-(FLOOR(SYSDATE - CREATED_DATE)))*24
         ) - 
         FLOOR((((SYSDATE - CREATED_DATE)-(FLOOR(SYSDATE - CREATED_DATE)))*24))
       )*60
    )
|| ' minutes'  
AS AGE FROM MyTable`

它以 x 年、x 月、x 天、x 小时、x 分钟的形式提供输出。可以通过更改连接的字符串来重新格式化它。

为了更直接地回答这个问题,我继续写了如何将总小时数与分钟数作为hours.minutes

select  
((FLOOR(end_date - start_date))*24)
|| '.' ||
ROUND(
       (
         (
           ((end_date - start_date)-(FLOOR(end_date - start_date)))*24
         ) - 
         FLOOR((((end_date - start_date)-(FLOOR(end_date - start_date)))*24))
       )*60
    )
from 
come_leav;   

【讨论】:

以上是关于如何在oracle中减去2个日期以获得小时和分钟的结果的主要内容,如果未能解决你的问题,请参考以下文章

PHP,需要从 DateTime 中减去 12 小时 30 分钟

在 matplotlib 轴上格式化日期时间以获得小时和分钟的问题

如何获得以秒或分钟或小时为单位的时差? [复制]

Oracle DB 中的日期时间格式不正确,转换为小时和分钟

oracle中计算两个日期的相差天数月数年数小时数分钟数秒数等

如何在 Oracle 中以 12 小时格式存储日期的 2 个日期之间的小时时差?