【问题标题】:SQL Server - calculate elapsed time between two datetime stamps in HH:MM:SS formatSQL Server - 以 HH:MM:SS 格式计算两个日期时间戳之间的经过时间
【发布时间】:2025-12-10 05:30:02
【问题描述】:

我有一个包含“时间”列的 SQL Server 表。该表是一个日志表,其中包含状态消息和每条消息的时间戳。日志表通过批处理文件插入。有一个 ID 列将行分组在一起。每次批处理文件运行时,它都会初始化 ID 并写入记录。我需要做的是获取从 ID 集中的第一条记录到同一 ID 集中的最后一条记录的经过时间。我开始从 logTable where id = 中选择 Max(Time) - Min(Time),但无法弄清楚如何正确格式化它。我在 HH:MM:SS 中需要它。

【问题讨论】:

  • 请告诉我们“时间”列的数据类型。 DateTime、DateTime2、时间、时间戳等

标签: sql-server-2008 datetime elapsedtime


【解决方案1】:

更新:

在 SQL Server 中正确计算时间跨度,即使超过 24 小时

-- Setup test data
declare @minDate datetime = '2012-12-12 20:16:47.160'
declare @maxDate datetime = '2012-12-13 15:10:12.050'

-- Get timespan in hh:mi:ss
select cast(
        (cast(cast(@maxDate as float) - cast(@minDate as float) as int) * 24) /* hours over 24 */
        + datepart(hh, @maxDate - @minDate) /* hours */
        as varchar(10))
    + ':' + right('0' + cast(datepart(mi, @maxDate - @minDate) as varchar(2)), 2) /* minutes */
    + ':' + right('0' + cast(datepart(ss, @maxDate - @minDate) as varchar(2)), 2) /* seconds */

-- Returns 18:53:24

特别欢迎显示不准确的边缘案例!

【讨论】:

  • @Tim....这几乎可以工作。对于这两个日期(2012-12-13 15:10:12.050 和 2012-12-12 20:16:47.160),当实际值为 18:53:24 时,您的查询返回了 19:54:25 的结果。想法?
  • @MikeTWebb 如果您不想使用函数或限制可以表示的小时数,您可能会发现当前版本运行良好。
【解决方案2】:

SQL Server 不支持 SQL 标准间隔数据类型。最好的办法是以秒为单位计算差异,并使用函数来格式化结果。 只要您的时间间隔小于 24 小时,本机函数 CONVERT() 就可以正常工作。但是 CONVERT() 不是一个好的解决方案。

create table test (
  id integer not null,
  ts datetime not null
  );

insert into test values (1, '2012-01-01 08:00');
insert into test values (1, '2012-01-01 09:00');
insert into test values (1, '2012-01-01 08:30');
insert into test values (2, '2012-01-01 08:30');
insert into test values (2, '2012-01-01 10:30');
insert into test values (2, '2012-01-01 09:00');
insert into test values (3, '2012-01-01 09:00');
insert into test values (3, '2012-01-02 12:00');

值的选择方式使得

  • id = 1,经过的时间是1小时
  • id = 2,经过时间为 2 小时,并且
  • id = 3,经过时间为 3 小时。

此 SELECT 语句包括一个计算秒数的列,以及一个使用 CONVERT() 进行减法运算的列。

select t.id,
       min(ts) start_time,
       max(ts) end_time,
       datediff(second, min(ts),max(ts)) elapsed_sec,
       convert(varchar, max(ts) - min(ts), 108) do_not_use
from test t
group by t.id;

ID  START_TIME                 END_TIME                   ELAPSED_SEC  DO_NOT_USE
1   January, 01 2012 08:00:00  January, 01 2012 09:00:00  3600         01:00:00
2   January, 01 2012 08:30:00  January, 01 2012 10:30:00  7200         02:00:00
3   January, 01 2012 09:00:00  January, 02 2012 12:00:00  97200        03:00:00

请注意具有误导性的“03:00:00”,因为 ID 号 3 的 27 小时差异。

Function to format elapsed time in SQL Server

【讨论】:

  • @Catcall....问题:您的查询适用于这两个跨越两天的日期(2012-12-13 15:10:12.050 和 2012-12-12 20:16:47.160 )。您的结果是 68005 秒和 18:53:24。这看起来是对的。不知道为什么 do_not_use 18:53:24 在那里?
  • CONVERT() 返回超过 24 小时间隔的错误答案。您的两个时间戳之间的差异小于 24 小时。 “do_not_use”列旨在阻止您使用 CONVERT() 来格式化间隔。
  • @Catcall...是的,我理解“do_not_use”列的含义。我对 CONVERT() 很好奇……你的解释很完美。谢谢!
  • 转换查询中的 108 代表什么?
  • @tiqa: 108 是style argument to CONVERT()。 ("hh:mi:ss")
【解决方案3】:
DECLARE @EndTime AS DATETIME, @StartTime AS DATETIME

SELECT @StartTime = '2013-03-08 08:00:00', @EndTime = '2013-03-08 08:30:00'

SELECT CAST(@EndTime - @StartTime AS TIME)

结果:00:30:00.0000000

按照您认为合适的格式设置结果。

【讨论】:

  • 这仅适用于 SQL Server 2008+,但假设您可以保证版本,这是一个很好的解决方案。
  • 时间大于24小时会失败
【解决方案4】:

最好最简单的方法:

Convert(varchar, {EndTime} - {StartTime}, 108)

就像 Anri 所说的那样。

【讨论】:

    【解决方案5】:

    使用 DATEDIFF 以毫秒、秒、分钟、小时、...为单位返回值

    DATEDIFF(时间间隔, date1, date2)

    间隔 必需 - 要返回的时间/日期部分。可以是以下值之一:

    year, yyyy, yy = Year
    quarter, qq, q = Quarter
    month, mm, m = month
    dayofyear = Day of the year
    day, dy, y = Day
    week, ww, wk = Week
    weekday, dw, w = Weekday
    hour, hh = hour
    minute, mi, n = Minute
    second, ss, s = Second
    millisecond, ms = Millisecond
    

    date1, date2 REQUIRED - 计算两个日期之间的差值

    【讨论】:

      【解决方案6】:

      select convert(varchar, Max(Time) - Min(Time) , 108) from logTable where id=...

      【讨论】:

        【解决方案7】:

        看看这是否有帮助。我可以为经过的天数、小时、分钟、秒设置变量。 您可以根据自己的喜好对其进行格式化或包含在用户定义的函数中。

        注意:不要使用 DateDiff(hh,@Date1,@Date2)。这不可靠!它以不可预知的方式循环

        给定两个日期... (示例日期:两天,三小时,10 分钟,30 秒时差)

        declare @Date1 datetime = '2013-03-08 08:00:00'
        declare @Date2 datetime = '2013-03-10 11:10:30'
        declare @Days decimal
        declare @Hours decimal
        declare @Minutes decimal
        declare @Seconds decimal
        
        select @Days = DATEDIFF(ss,@Date1,@Date2)/60/60/24 --Days
        declare @RemainderDate as datetime = @Date2 - @Days
        select @Hours = datediff(ss, @Date1, @RemainderDate)/60/60 --Hours
        set @RemainderDate = @RemainderDate - (@Hours/24.0)
        select @Minutes = datediff(ss, @Date1, @RemainderDate)/60 --Minutes
        set @RemainderDate = @RemainderDate - (@Minutes/24.0/60)
        select @Seconds = DATEDIFF(SS, @Date1, @RemainderDate)    
        select @Days as ElapsedDays, @Hours as ElapsedHours, @Minutes as ElapsedMinutes, @Seconds as ElapsedSeconds
        

        【讨论】:

          【解决方案8】:

          希望这可以帮助您获得两个时间戳之间的确切时间

          Create PROC TimeDurationbetween2times(@iTime as time,@oTime as time) 
          As  
          Begin  
          
          DECLARE @Dh int, @Dm int, @Ds int ,@Im int, @Om int, @Is int,@Os int     
          
          SET @Im=DATEPART(MI,@iTime)  
          SET @Om=DATEPART(MI,@oTime)  
          SET @Is=DATEPART(SS,@iTime)  
          SET @Os=DATEPART(SS,@oTime)  
          
          SET @Dh=DATEDIFF(hh,@iTime,@oTime)  
          SET @Dm = DATEDIFF(mi,@iTime,@oTime)  
          SET @Ds = DATEDIFF(ss,@iTime,@oTime)  
          
          DECLARE @HH as int, @MI as int, @SS as int  
          
          if(@Im>@Om)  
          begin  
          SET @Dh=@Dh-1  
          end  
          if(@Is>@Os)  
          begin  
          SET @Dm=@Dm-1  
          end  
          
          SET @HH = @Dh  
          SET @MI = @Dm-(60*@HH)  
          SET @SS = @Ds-(60*@Dm)  
          
          DECLARE @hrsWkd as varchar(8)         
          
          SET @hrsWkd = cast(@HH as char(2))+':'+cast(@MI as char(2))+':'+cast(@SS as char(2))          
          
          select @hrsWkd as TimeDuration   
          
          End
          

          【讨论】: