Calculating Month Difference

Itzik addresses a reader request to calculate the difference in terms of months between two dates.

Itzik Ben-Gan

February 26, 2009

8 Min Read
ITPro Today logo in a gray background | ITPro Today

Recently I got a request from a reader to calculate the difference in terms of months between two dates in order to work out how many standing order/direct debit payments should have been received. (See also, "Correctly Calculating Datetime Differences" and "Manipulate and Calculate.")

I’ll provide a solution using a scalar UDF called NumPayments. The function accepts two inputs: @startdate (the standing order/direct debit start date), and @enddate (the date that the calculation should be checked against—typically the date when the query is run). Here’s the function’s header:

CREATE FUNCTION dbo.NumPayments

(

  @startdate AS DATETIME,

  @enddate   AS DATETIME

) RETURNS INT

 

The logic behind the calculation is actually quite straightforward. First calculate the difference in terms of months between the starting year-and-month and the ending year-and-month, then add 1 to account for both the starting month and ending month. Then, subtract 1 in case the ending day is smaller than the starting day. Per the original request that I got, if the day part of the end date is on or after the day part of the start date, there is a payment in the end month, otherwise there isn’t. If the day part of the start date is greater than the maximum possible day part of a given month, the payment for that month happens on the first of the next month. The last part of the calculation handles this scenario correctly (subtract 1 in case the ending day is smaller than the starting day).

As an example, suppose you are given the following sample data representing different dates in which you make the request:

USE tempdb;

 

IF OBJECT_ID('dbo.SampleDates', 'U') IS NOT NULL

  DROP TABLE dbo.SampleDates;

 

CREATE TABLE dbo.SampleDates

(

  dt DATETIME NOT NULL PRIMARY KEY

);

GO

 

INSERT INTO dbo.SampleDates(dt)

            SELECT '20090228'

  UNION ALL SELECT '20090301'

  UNION ALL SELECT '20090429'

  UNION ALL SELECT '20090430'

  UNION ALL SELECT '20090501';

 

And you run the following query to calculate how many standing order/direct debit payments should have been received by the date in the table, for a start date of October 30th, 2008:

DECLARE @startdate AS DATETIME;

SET @startdate = '20081030';

 

SELECT

  @startdate AS startdate, dt AS enddate,

  dbo.NumPayments(@startdate, dt) AS payments

FROM dbo.SampleDates;

 

You are supposed to get the following output:

startdate               enddate                 payments

----------------------- ----------------------- -----------

2008-10-30 00:00:00.000 2009-02-28 00:00:00.000 4

2008-10-30 00:00:00.000 2009-03-01 00:00:00.000 5

2008-10-30 00:00:00.000 2009-04-29 00:00:00.000 6

2008-10-30 00:00:00.000 2009-04-30 00:00:00.000 7

2008-10-30 00:00:00.000 2009-05-01 00:00:00.000 7

 

Here’s the definition of the UDF that I used to address this calculation:

IF OBJECT_ID('dbo.NumPayments', 'FN') IS NOT NULL

  DROP FUNCTION dbo.NumPayments;

GO

CREATE FUNCTION dbo.NumPayments

(

  @startdate AS DATETIME,

  @enddate   AS DATETIME

) RETURNS INT

AS

BEGIN

  RETURN

    DATEDIFF(month, @startdate, @enddate)

      - CASE

          WHEN DAY(@enddate) < DAY(@startdate) THEN 1

          ELSE 0

        END

      + 1;

END

GO

 

As you can see, it’s pretty much a literal translation of the calculation I described earlier, and as such is simple and straightforward. The code uses the DATEDIFF function to calculate the difference in terms of months between @startdate and @enddate and adds 1 to account for both starting month and ending month. The code then subtracts the result of a CASE expression that returns 1 in case the day part of @enddate is smaller than the day part of @startdate and 0 otherwise. If you run the code provided above to test the function, you will get the desired output.

Cheers,

BG

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like