# Difference between dates in Months and Days [closed]

I've written a function that returns how many Months and Days are between two dates. I want to respect calendar month boundaries, but I'm ignoring time as it's not relevant for my needs.

I've got the following, but I feel like I'm missing thing I can do to optimize it/refactor it. So I'm looking for additional eyes to help me review this.

//As opposed to TimeSpan ^_^
{
public CalendarSpan(int months, int days)
{
Months = months;
Days = days;
}
}

public static CalendarSpan DifferenceInMonthsAndDays(DateTime startDate, DateTime endDate)
{
//Ensuring that the larger of two dates is the latter argument
if (startDate > endDate)
return DifferenceInMonthsAndDays(endDate, startDate);

var months = 12 * (endDate.Year - startDate.Year) + endDate.Month - startDate.Month;

int days;
//Add the difference in months to the smaller of the two dates
//So long as we can avoid negative numbers, just do the simple math
else
{
//Otherwise, backoff by 1 months, and use the built in Subtract logic to get the number of days between the two dates
months--;
}

return new CalendarSpan(months, days);
}


UPDATE I have been trying to get unit tests for this, and I honestly don't know why I ever attempted this. It is NOT an easy or straight forward thing to do at all. Insert obligatory meme of Homer disappearing into the hedges

• This will give the same span for some combinations of dates (e.g. May 30 -> Jun 30 and May 31 -> Jun 30 will both give 1 month 0 days because AddMonths will return the last day of the month if the calculated day does not exist). Is this expected/acceptable behavior? – 1201ProgramAlarm Jul 25 '19 at 3:09
• You mention as opposed to timespan, but you don't justify why. – tinstaafl Jul 25 '19 at 3:26
• Can you add some unit tests to show what output you would expect? For example with 30.01.2019 and 01.12.2019 your solution gives 10 months, 1 day but I could imagine that 10 months and 2 days would be equally likely, depending on where you start. – poke Jul 25 '19 at 10:32
• “It is NOT an easy or straight forward thing to do at all.” – Welcome to the world of calendar dates… 😂 – poke Jul 26 '19 at 7:45
• I've voted to close this because I think it is impossible to comment on the suitability of the code without a better specification. – VisualMelon Jul 26 '19 at 12:33

1. CalendarSpan signed (date1 > date2 => negative span)
2. Extension overload of DateTime.Add() taking CalendarSpan argument
3. Unit test approach (see Main() which iterates positive and negative differences, using DateTime functions to check integrity of results)



using System;

namespace DateDiff
{
static class Program
{
{
public CalendarSpan(int months, int days)
{
Months = months;
Days = days;
}
}

//  Maintains sign-consistency, i.e. if l > r returned value components are positive and if l < r negative
public static CalendarSpan MonthDaysDifference(this DateTime l, DateTime r)
{
var mDiff = l.Month - r.Month + 12 * (l.Year - r.Year);

var dDiff = (l - r.AddMonths(mDiff)).Days;
if (dDiff == 0 //  no day, the span is a whole number of months
|| l > r && dDiff > 0 //  day and month differences ...
|| l < r && dDiff < 0) //  ... have the same sign
return new CalendarSpan(mDiff, dDiff);
//  Signs differ
var dSign = Math.Sign(dDiff);
var mSign = Math.Sign(mDiff);
//  It doesn't matter which sign is which, we adjust months in the correct direction
mDiff += dSign;
//  and recalculate days
return new CalendarSpan(mDiff, (l - r.AddMonths(mDiff)).Days);
}

public static DateTime Add(this DateTime dt, CalendarSpan span)
{
}

//  Included to suggest how to test
static void Main(string[] args)
{
for (int i = 0; i < 1000; i++)
{
var date1 = new DateTime(2017, 12, 25).AddDays(i);
for (int j = 0; j < 1000; j++)
{
var date2 = new DateTime(2019, 01, 01).AddDays(j);
var dateDiff = date1.MonthDaysDifference(date2);
//var dateDiff2 = MonthDaysDifference(date1,date2);//just checking
Console.WriteLine($"ERROR: {date1:yyyy-MM-dd} - {date2:yyyy-MM-dd} = {dateDiff.Months} months + {dateDiff.Days} days"); Console.WriteLine("Any key to exit"); Console.ReadKey(); return; } Console.WriteLine($"{date1:yyyy-MM-dd} - {date2:yyyy-MM-dd} = {dateDiff.Months} months + {dateDiff.Days} days");
`