HH:MM:SS格式的DATEDIFF

时间:2013-01-21 19:13:51

标签: sql sql-server sql-server-2008 date datetime

我需要以小时数,分钟数,秒数和平均长度来计算总长度,给出一些包含开始时间和结束时间的数据。

例如,结果必须是45:15:10,这意味着45小时15分10秒,或30:07 30分钟07秒。

我们正在使用SQL Server 2008 R2,当时间超过24:59:59时转换失败。知道如何做到这一点吗?

有关信息,表格中的列为IdStartDateTimeEndDateTime等。我需要制作月度报告,其中包含当月的记录数,总数这些记录的长度和平均长度。我想知道是否有一种简单的方法来执行所有这些。

5 个答案:

答案 0 :(得分:9)

你不应该转换为time - 它意味着在一个24小时的时钟上存储一个时间点,而不是一个持续时间或间隔(即使是一个受限于它自己到<24小时的时间) ,显然你的数据不是)。相反,你可以在所需的最小间隔(在你的情况下,秒)中采用datediff,然后执行一些数学和字符串操作,以你需要的输出格式呈现它(也可能最好将秒返回给应用程序或报告工具并让它完成这项工作)。

DECLARE @d TABLE
(
  id INT IDENTITY(1,1), 
  StartDateTime DATETIME, 
  EndDateTime DATETIME
);

INSERT @d(StartDateTime, EndDateTime) VALUES 
(DATEADD(DAY, -2, GETDATE()), DATEADD(MINUTE, 15, GETDATE())),
(GETDATE()                  , DATEADD(MINUTE, 22, GETDATE())),
(DATEADD(DAY, -1, GETDATE()), DATEADD(MINUTE,  5, GETDATE())),
(DATEADD(DAY, -4, GETDATE()), DATEADD(SECOND, 14, GETDATE()));

;WITH x AS (SELECT id, StartDateTime, EndDateTime, 
  d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
  a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
  FROM @d
)
SELECT id, StartDateTime, EndDateTime,
  [delta_HH:MM:SS] = CONVERT(VARCHAR(5), d/60/60)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
  [avg_HH:MM:SS] = CONVERT(VARCHAR(5), a/60/60)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;

结果:

id  StartDateTime        EndDateTime          delta_HH:MM:SS  avg_HH:MM:SS
--  -------------------  -------------------  --------------  ------------
1   2013-01-19 14:24:46  2013-01-21 14:39:46  48:15:00        42:10:33
2   2013-01-21 14:24:46  2013-01-21 14:46:46   0:22:00        42:10:33
3   2013-01-20 14:24:46  2013-01-21 14:29:46  24:05:00        42:10:33
4   2013-01-17 14:24:46  2013-01-21 14:25:00  96:00:14        42:10:33

这不正是你所要求的,因为它不会只显示MM:SS for deltas&lt; 1小时。您可以使用简单的CASE表达式进行调整:

;WITH x AS (SELECT id, StartDateTime, EndDateTime, 
  d = DATEDIFF(SECOND, StartDateTime, EndDateTime),
  a = AVG(DATEDIFF(SECOND, StartDateTime, EndDateTime)) OVER()
  FROM @d
)
SELECT id, StartDateTime, EndDateTime,
  [delta_HH:MM:SS] = CASE WHEN d >= 3600 THEN 
    CONVERT(VARCHAR(5), d/60/60) + ':' ELSE '' END
  + RIGHT('0' + CONVERT(VARCHAR(2), d/60%60), 2)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), d % 60), 2),
  [avg_HH:MM:SS] = CASE WHEN a >= 3600 THEN 
    CONVERT(VARCHAR(5), a/60/60) + ':' ELSE '' END
  + RIGHT('0' + CONVERT(VARCHAR(2), a/60%60), 2)
  + ':' + RIGHT('0' + CONVERT(VARCHAR(2), a % 60), 2)
FROM x;

此查询将上述结果中第二行的增量列从0:22:00更改为22:00

答案 1 :(得分:2)

我略微修改了Avinash的答案,因为如果差异太大,它可能会以错误结束。如果您只需要HH:mm:ss就足以区分秒级别,如下所示:

SELECT CONVERT(time, 
  DATEADD(s, 
    DATEDIFF(s, 
      '2018-01-07 09:53:00', 
      '2018-01-07 11:53:01'), 
     CAST('1900-01-01 00:00:00.0000000' as datetime2)
   )
)

答案 2 :(得分:1)

如果你想做平均值,那么最好的方法是转换为秒或一天的分数。在SQL Server中,日分数很方便,因为您可以执行以下操作:

select avg(cast(endtime - starttime) as float)
from t

您可以使用反向投射将其转换回datetime

select cast(avg(cast(endtime - starttime as float) as datetime)
from t

以您想要的格式获取时间的算法。 。 。那是一种痛苦。您可以考虑在最终格式中包含天数,并使用:

select right(convert(varchar(255), <val>, 120), 10)

要获得超过24小时,这是另一种方法:

select cast(floor(cast(<val> as float)*24) as varchar(255))+right(convert(varchar(255), <val>, 120), 6)

它使用convert分钟和秒,应在左侧填充0。然后它将小时数作为单独的值附加。

答案 3 :(得分:0)

一种避免溢出的方法,可以包括几天,并在输出中一直到毫秒:

DECLARE @startDate AS DATETIME = '2018-06-01 14:20:02.100'
DECLARE @endDate AS DATETIME = '2018-06-02 15:23:09.000'
SELECT CAST(DATEDIFF(day,'1900-01-01', @endDate - @startDate) AS VARCHAR) +  'd ' + CONVERT(varchar(22), @endDate - @startDate, 114)

以上将返回

  

1d 01:03:06:900

而且,当然,您可以使用您选择的格式

SQL支持datetime substraction,它输出相对于MIN日期的新日期时间(例如1900-01-01,您可以从某个系统变量中获取此值)这比DATEDIFF更好,因为DATEDIFF将为每个计数一个即使经过的时间小于整个数据空间,也会“越过日期部分边界”。这种方法的另一个好处是它允许您使用日期格式转换。

答案 4 :(得分:0)

从SQL SERVER 2012开始,您不需要使用DATEDIFF函数。您可以使用FORMAT函数来实现所需的功能:

SELECT
    FORMAT(CONVERT(TIME, [appoitment].[Start] - [appointment].[End]), N'hh\:mm') AS 'Duration'
FROM
    [tblAppointment] (NOLOCK)