T-SQL Ninja #48

DATEDIFF

What does DATEDIFF do?

Today we’ll look at one of the most well-known and really frequently used functions in SQL Server: DATEDIFF. The DATEDIFF function belongs to the functions for time objects, with it you can calculate the time between two datetime timestamps. You are free to specify the interval in years, months, days, hours, minutes, seconds, milliseconds or nanoseconds, only the return value must be in the value range of INT.

How can you work with DATEDIFF?

As already mentioned, the DATEDIFF function calculates the distance between two DateTime values. Let’s look at an example from the WideWorldImporters database in the Sales.Orders table. If we want to know here how many days were between the first and the last order of a customer, i.e. how long the customer has been our customer, we can do this as follows

SELECT 
     MIN(OrderDate) AS MinOrderDate
    ,MAX(OrderDate) AS MaxOrderDate
    ,DATEDIFF(DAY, MIN(OrderDate), MAX(OrderDate)) as DaysBetweenOrders
    ,CustomerID 
FROM Sales.Orders
GROUP BY CustomerID
ORDER BY DATEDIFF(DAY, MIN(OrderDate), MAX(OrderDate)) DESC

Of course, we can also have this time interval displayed in months or years:

SELECT 
     MIN(OrderDate) AS MinOrderDate
    ,MAX(OrderDate) AS MaxOrderDate
    ,DATEDIFF(DAY, MIN(OrderDate), MAX(OrderDate)) as DaysBetweenOrders
    ,DATEDIFF(MONTH, MIN(OrderDate), MAX(OrderDate)) as MonthsBetweenOrders
    ,DATEDIFF(YEAR, MIN(OrderDate), MAX(OrderDate)) as YearsBetweenOrders
    ,CustomerID 
FROM Sales.Orders
GROUP BY CustomerID
ORDER BY DATEDIFF(DAY, MIN(OrderDate), MAX(OrderDate)) DESC

But we can also look at how long ago a customer’s last order was placed, for example:

SELECT 
     MIN(OrderDate) AS MinOrderDate
    ,MAX(OrderDate) AS MaxOrderDate
    ,DATEDIFF(DAY, MAX(OrderDate), GETDATE()) as DaysSinceLastOrder
    ,CustomerID 
FROM Sales.Orders
GROUP BY CustomerID
ORDER BY DATEDIFF(DAY, MAX(OrderDate), GETDATE()) DESC

If you now want to calculate how much time was on average between the orders of a customer, you can do this with a CTE:

;WITH cte_dates AS (
    SELECT 
         DATEDIFF(DAY, 
            OrderDate, 
            LEAD(OrderDate, 1) OVER (PARTITION BY CustomerID ORDER BY OrderDate)
         ) DaysBetweenOrders
        ,CustomerID 
    FROM Sales.Orders
)
SELECT 
     AVG(CAST(DaysBetweenOrders AS decimal(10,2)))
    ,CustomerID
FROM cte_dates
GROUP BY CustomerID

But as written above, this only works as long as the return value is within the value range of INT. You can determine the maximum value for an integer in SQL as follows:

SELECT -1-POWER(-2,31);

This gives us the value 2147483647, so if we look at the nanosecond portion of time, two dates between which we want to determine the nanoseconds can be a maximum of 2.15 seconds apart. Let’s try this, the following query returns an overflow error:

DECLARE @currentDate datetime = GETDATE()
SELECT DATEDIFF(NANOSECOND, DATEADD(SECOND, -3, @currentDate), @currentDate)

However, if we reduce the time window to 2 seconds, we get a result:

DECLARE @currentDate datetime = GETDATE()
SELECT DATEDIFF(NANOSECOND, DATEADD(SECOND, -2, @currentDate), @currentDate)

Let us now consider the maximum distance between two timestamps when they are separated by the maximum INT value in milliseconds or seconds:

DECLARE @MaxInt int = -1-POWER(-2,31);
DECLARE @currentDate datetime = GETDATE()

SELECT 
     DATEDIFF(HOUR, @currentDate, DATEADD(MILLISECOND, @MaxInt, @currentDate)) MaxMSHours
    ,DATEDIFF(DAY, @currentDate, DATEADD(MILLISECOND, @MaxInt, @currentDate)) MaxMSDays
    ,DATEDIFF(YEAR, @currentDate, DATEADD(MILLISECOND, @MaxInt, @currentDate)) MaxMSYears
    ,DATEDIFF(HOUR, @currentDate, DATEADD(SECOND, @MaxInt, @currentDate)) MaxSHours
    ,DATEDIFF(DAY, @currentDate, DATEADD(SECOND, @MaxInt, @currentDate)) MaxSDays
    ,DATEDIFF(YEAR, @currentDate, DATEADD(SECOND, @MaxInt, @currentDate)) MaxSYears

You can see that two timestamps that you want to know the distance in milliseconds can be a maximum of 25 days apart, while two timestamps that you want to know the distance in seconds can be a maximum of 68 years apart before the overflow of INT occurs. That’s pretty granular for such time spans.

References

Ninja-Notebooks @ GitHub

Leave a Reply

Your email address will not be published. Required fields are marked *