Here you go. The DATEDIFF is only called once - which makes a difference in large queries. No CONVERT, but 4 FORMATS. Not sure if that makes a difference. Each part is optional. You can easily remove the optional code to slim it down. I suppose you could even write separate functions and remove the optional code for whatever you need, link
dbo.GetElapsedTimeHM
to return only hh:mm
alter function dbo.GetElapsedTime(@Start datetime, @End datetime,
@d bit = 0, @h bit = 1, @m bit = 1, @s bit = 1)
returns varchar(11) as
begin
/*
declare @Start datetime, @End datetime, @d bit = 1, @h bit = 1, @m bit = 1, @s bit = 1
set @Start = '2023-05-24 16:34:22.900'
set @End = '2023-05-26 13:57:43.070'
select dbo.GetElapsedTime(@Start, @End, 1,1,1,1)
select dbo.GetElapsedTime(@Start, @End, @d, @h, @m, @s)
*/
declare @result varchar(11)
;with totalsecs as (select DATEDIFF(s, @Start, @End) as NumOfSecs
), DayNum as (select (NumOfSecs / 86400) * 86400 as DaySecs from totalsecs
), hrs as (select ((NumOfSecs - DaySecs) / 3600) * 3600 as HrSecs from DayNum, totalsecs
), Mins as (select ((NumOfSecs - DaySecs - HrSecs) / 60) * 60 as MinSecs from hrs, DayNum, totalsecs
), secs as (select NumOfSecs - DaySecs - HrSecs - MinSecs as SecSecs from mins, hrs, DayNum, totalsecs
)
select @result =
case @d when 1 then RIGHT('0' + FORMAT(DaySecs / 86400, ''), 2) else '' end
+ case when @d = 1 and @h = 1 then ':' else '' end
+ case @h when 1 then RIGHT('0' + FORMAT(HrSecs / 3600, ''), 2) else '' end
+ case when (@d = 1 or @h = 1) and @m = 1 then ':' else '' end
+ case @m when 1 then RIGHT('0' + FORMAT(MinSecs / 60, ''), 2) else '' end
+ case when (@d = 1 or @h = 1 or @m = 1) and @s = 1 then ':' else '' end
+ case @s when 1 then RIGHT('0' + FORMAT(SecSecs, ''), 2) else '' end
from secs, mins, hrs, DayNum, totalsecs
return @result
--select @result
end