Home > SQL > Human Readable DateDiff

Human Readable DateDiff

March 12th, 2009

The DateDiff function is frustrating.  You can only get a single element (seconds, minutes, hours, days, months or years).  At work we currently use the DateDiff function for DTS statistics.  Its handy cause you can get an idea of where your spending your time durring DTS execution.  However, it’s not very reasonable.  I wanted a function to return Human Readable text…not just the number of seconds or minutes between dates.

WireLust has a good article here.  However this function uses DATEDIFF and this function has its flaws.

Take a look at this…

SELECT dbo.DateDiffHumanReadable('11:50:48.000', '12:12:45.000', 's')

RESULT
----------------------
1h

(1 row(s) affected)

The code below is my implementation of a HumanReadable DateDiff. There are imperfections with the DateDiff function. My function gets the total seconds between 2 dates and derives the Seconds, Minutes, Hours and Days. Since we use the function for DTS Execution metrics we don’t need anything more than hours…but I included days cause it was easy to do.

My function would return this…

SELECT dbo.DateDiffHumanReadable('11:50:48.000', '12:12:45.000'c)

RESULT
----------------------
21m 57s 

(1 row(s) affected)

So here it is the Improved Human Readable DateDiff…

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		ADAM CLARK
-- Create date: 3/12/2009
-- Description:	Generates a human readable
--				difference between two dates
-- =============================================
CREATE FUNCTION [dbo].[dateDiffHumanReadable]
(
		@dateStart DATETIME,
		@dateEnd DATETIME
)
RETURNS VARCHAR(200)
AS
BEGIN
	DECLARE
		@diffAsString VARCHAR(200),
		@TotalSeconds INT

	DECLARE
		@day INT,
		@hour INT,
		@minute INT,
		@second INT

	SET @second = 0
	SET @minute = 0
	SET @hour = 0
	SET @day = 0

	SET @diffAsString = ''
	IF (@dateStart IS NULL OR @dateEnd IS NULL) BEGIN
		RETURN @diffAsString
	END

	SET @TotalSeconds = DATEDIFF(ss, @dateStart, @dateEnd);
	IF (@TotalSeconds < 0) BEGIN
		RETURN 'ERR: StartDate After EndDate'
	END

	-- seconds
	IF @TotalSeconds < 60 BEGIN
		SET @second = @TotalSeconds
	END
	ELSE BEGIN
		SET @minute = @TotalSeconds / 60
		SET @second = @TotalSeconds - (@minute * 60)

		-- minutes
		IF @minute > 59 BEGIN
			SET @hour = @minute / 60
			SET @minute = @minute - (@hour * 60)

			--hours
			IF @hour > 23 BEGIN
				SET @day = @hour / 24
				SET @hour = @hour - (@day * 24)
			END
		END
	END

	-- Build the output string
	IF @day <> 0 BEGIN
		SET @diffAsString = @diffAsString + CAST(@day AS VARCHAR(10)) + 'd ' + CAST(@hour AS VARCHAR(10)) + 'h ' + CAST(@minute AS VARCHAR(10)) + 'm ' + CAST(@second AS VARCHAR(10)) + 's '
	END
	ELSE BEGIN
		IF @hour <> 0 BEGIN
			SET @diffAsString = @diffAsString + CAST(@hour AS VARCHAR(10)) + 'h ' + CAST(@minute AS VARCHAR(10)) + 'm ' + CAST(@second AS VARCHAR(10)) + 's '
		END
		ELSE BEGIN
			IF @minute <> 0 BEGIN
				SET @diffAsString = @diffAsString + CAST(@minute AS VARCHAR(10)) + 'm ' + CAST(@second AS VARCHAR(10)) + 's '
			END
			ELSE BEGIN
				IF @second <> 0 BEGIN
					SET @diffAsString = @diffAsString + CAST(@second AS VARCHAR(10)) + 's '
				END
				ELSE BEGIN
					SET @diffAsString = '0s'
				END
			END
		END
	END
	RETURN @diffAsString
END
GO

  1. Tea
    March 12th, 2009 at 15:43 | #1

    hey, good to see someone is making use of my code I post.

    What is the problem with the datediff function that makes you want to use it less?

    I had originally coded the function more like yours where you datediff to get the smallest increment first (ms in my case) but this is problematic because it gets an overflow error when the number is too big. With ‘ms’, it will overflow at like 10 years, with ’s’ it takes almost 100 years. My particular application I needed to have accuracy to ‘ms’ for up to 20 years.

    As an example, dateDiffHumanReadableAdam is your version and overflows on this large date span.

    DECLARE @birthday DATETIME
    SET @birthday = ‘6/2/1910 16:00:00′
    PRINT dbo.dateDiffHumanReadable(@birthday, GETDATE(), ‘ms’)
    PRINT dbo.dateDiffHumanReadableAdam(@birthday, GETDATE())

    • March 12th, 2009 at 16:38 | #2

      Honestly, I needed a function to process date differences that are no more than a week long…honestly not more than a day long. If I have a DTS package that runs longer than a day…I’m in trouble. As for why I didn’t want to use your function…or DATEDIFF for that matter…check the post. Your function returns 1h for time span that should be 21m 57s.

  2. Tea
    March 12th, 2009 at 18:00 | #3

    Ahhh. good catch. I didn’t see your comment about it returning 1d, which is incorrect.

    I was under the mistaken thinking that
    SELECT DATEDIFF(hour, ‘11:50:48.000′, ‘12:12:45.000′)
    would return 0, when in fact it returns 1.

    I updated my function to use DATEDIFF to lop off the year, then use a ms calculation to count up like yours. This way it works for long time spans as well as short. I should spend some time testing though to see if there are any other problems with it.

  1. March 12th, 2009 at 18:03 | #1