How to calculate the actual difference between months (calendar year, not approximation) between two given dates in C #?

Example: if two dates are indicated below, the finish is always greater than or equal to the start

start = 2001 January 01

finish = 2002 Mar 15

So, from 2001 January 01 to the end of February February

months = 12 + 2 = 14

In March 2002

15/30 = 0.5

so the total amount is 14.5 months.

It’s very easy to understand the hand, but how can I prescribe it? At the moment, I have a lot of combinations, if also while loops to achieve what I want, but I believe that there are simpler solutions.

Update: the output should be accurate (not approximation), for example: if the beginning of January 2001 is 01 and 2001 ends April 16, the output should be 1 + 1 + 1 = 3 (for January, February and March) and 16/31 = 0.516 months , so the total number is 3.516.

Another example would be if I start in 2001 on July 5 and finish in 2002 on July 10, the release should be 11 months before the end of June 2002 and (31-5) / 31 = 0.839 and 10/31 = 0.323 months, therefore the total value is 11 + 0.839 + 0.323 = 12.162.

I have expanded the Josh Stodola code and the Hightechrider code :

public static decimal GetMonthsInRange(this IDateRange thisDateRange) { var start = thisDateRange.Start; var finish = thisDateRange.Finish; var monthsApart = Math.Abs(12*(start.Year - finish.Year) + start.Month - finish.Month) - 1; decimal daysInStartMonth = DateTime.DaysInMonth(start.Year, start.Month); decimal daysInFinishMonth = DateTime.DaysInMonth(finish.Year, finish.Month); var daysApartInStartMonth = (daysInStartMonth - start.Day + 1)/daysInStartMonth; var daysApartInFinishMonth = finish.Day/daysInFinishMonth; return monthsApart + daysApartInStartMonth + daysApartInFinishMonth; } 
+7
c # datetime
source share
11 answers

I gave an int answer earlier, and then realized that you asked for a more accurate answer. I was tired, so I retired and went to bed. So much for this, I could not fall asleep! For some reason, this question really listened to me, and I had to solve it. So you go ...

 static void Main(string[] args) { decimal diff; diff = monthDifference(new DateTime(2001, 1, 1), new DateTime(2002, 3, 15)); Console.WriteLine(diff.ToString("n2")); //14.45 diff = monthDifference(new DateTime(2001, 1, 1), new DateTime(2001, 4, 16)); Console.WriteLine(diff.ToString("n2")); //3.50 diff = monthDifference(new DateTime(2001, 7, 5), new DateTime(2002, 7, 10)); Console.WriteLine(diff.ToString("n2")); //12.16 Console.Read(); } static decimal monthDifference(DateTime d1, DateTime d2) { if (d1 > d2) { DateTime hold = d1; d1 = d2; d2 = hold; } int monthsApart = Math.Abs(12 * (d1.Year-d2.Year) + d1.Month - d2.Month) - 1; decimal daysInMonth1 = DateTime.DaysInMonth(d1.Year, d1.Month); decimal daysInMonth2 = DateTime.DaysInMonth(d2.Year, d2.Month); decimal dayPercentage = ((daysInMonth1 - d1.Day) / daysInMonth1) + (d2.Day / daysInMonth2); return monthsApart + dayPercentage; } 

Now I will have sweet dreams. Good night:)

+8
source share

What you want is probably something close to this ... which pretty much follows your explanation as to how to calculate it:

 var startofd1 = d1.AddDays(-d1.Day + 1); var startOfNextMonthAfterd1 = startofd1.AddMonths(1); // back to start of month and then to next month int daysInFirstMonth = (startOfNextMonthAfterd1 - startofd1).Days; double fraction1 = (double)(daysInFirstMonth - (d1.Day - 1)) / daysInFirstMonth; // fractional part of first month remaining var startofd2 = d2.AddDays(-d2.Day + 1); var startOfNextMonthAfterd2 = startofd2.AddMonths(1); // back to start of month and then to next month int daysInFinalMonth = (startOfNextMonthAfterd2 - startofd2).Days; double fraction2 = (double)(d2.Day - 1) / daysInFinalMonth; // fractional part of last month // now find whole months in between int monthsInBetween = (startofd2.Year - startOfNextMonthAfterd1.Year) * 12 + (startofd2.Month - startOfNextMonthAfterd1.Month); return monthsInBetween + fraction1 + fraction2; 

NB This has not been tested very well, but it shows how to deal with such problems by finding known dates at the beginning of the months around the meaning of the problems and then working them out.

Although loops for calculating time by date are always bad ideas: see http://www.zuneboards.com/forums/zune-news/38143-cause-zune-30-leapyear-problem-isolated.html

+2
source share

One way to do this is that you will see something like this:

 private static int monthDifference(DateTime startDate, DateTime endDate) { int monthsApart = 12 * (startDate.Year - endDate.Year) + startDate.Month - endDate.Month; return Math.Abs(monthsApart); } 

However, you need "incomplete months" that this does not give. But what's the point of comparing apples (January / March / May / July / August / October / December) with oranges (April / June / September / November) or even bananas, which are sometimes coconuts (February)?

An alternative is to import Microsoft.VisualBasic and do this:

  DateTime FromDate; DateTime ToDate; FromDate = DateTime.Parse("2001 Jan 01"); ToDate = DateTime.Parse("2002 Mar 15"); string s = DateAndTime.DateDiff (DateInterval.Month, FromDate,ToDate, FirstDayOfWeek.System, FirstWeekOfYear.System ).ToString(); 

However again:

The return value for DateInterval.Month is calculated purely from the year and month of the arguments

[A source]

+1
source share

Depending on how exactly you want your logic to work, this would at least give you a decent approximation:

 // 365 days per year + 1 day per leap year = 1461 days every 4 years // But years divisible by 100 are not leap years // So 1461 days every 4 years - 1 day per 100th year = 36524 days every 100 years // 12 months per year = 1200 months every 100 years const double DaysPerMonth = 36524.0 / 1200.0; double GetMonthsDifference(DateTime start, DateTime finish) { double days = (finish - start).TotalDays; return days / DaysPerMonth; } 
+1
source share

Josh's just improved answer

  static decimal monthDifference(DateTime d1, DateTime d2) { if (d1 > d2) { DateTime hold = d1; d1 = d2; d2 = hold; } decimal monthsApart = Math.Abs((12 * (d1.Year - d2.Year)) + d2.Month - d1.Month - 1); decimal daysinStartingMonth = DateTime.DaysInMonth(d1.Year, d1.Month); monthsApart = monthsApart + (1-((d1.Day - 1) / daysinStartingMonth)); // Replace (d1.Day - 1) with d1.Day incase you DONT want to have both inclusive difference. decimal daysinEndingMonth = DateTime.DaysInMonth(d2.Year, d2.Month); monthsApart = monthsApart + (d2.Day / daysinEndingMonth); return monthsApart; } 
+1
source share

The answer works just fine, and although code compression makes it very small, I had to break it down into smaller functions with named variables so that I can really understand what is happening ... So basically I just took Josh's code for Stodola and Hightechrider are mentioned in Jeff's comments also reduced it with comments explaining what happens and why the calculations are made, and hopefully this can help someone else:

  [Test] public void Calculate_Total_Months_Difference_Between_Two_Dates() { var startDate = DateTime.Parse( "10/8/1996" ); var finishDate = DateTime.Parse( "9/8/2012" ); // this should be now: int numberOfMonthsBetweenStartAndFinishYears = getNumberOfMonthsBetweenStartAndFinishYears( startDate, finishDate ); int absMonthsApartMinusOne = getAbsMonthsApartMinusOne( startDate, finishDate, numberOfMonthsBetweenStartAndFinishYears ); decimal daysLeftToCompleteStartMonthPercentage = getDaysLeftToCompleteInStartMonthPercentage( startDate ); decimal daysCompletedSoFarInFinishMonthPercentage = getDaysCompletedSoFarInFinishMonthPercentage( finishDate ); // .77 + .26 = 1.04 decimal totalDaysDifferenceInStartAndFinishMonthsPercentage = daysLeftToCompleteStartMonthPercentage + daysCompletedSoFarInFinishMonthPercentage; // 13 + 1.04 = 14.04 months difference. decimal totalMonthsDifference = absMonthsApartMinusOne + totalDaysDifferenceInStartAndFinishMonthsPercentage; //return totalMonths; } private static int getNumberOfMonthsBetweenStartAndFinishYears( DateTime startDate, DateTime finishDate ) { int yearsApart = startDate.Year - finishDate.Year; const int INT_TotalMonthsInAYear = 12; // 12 * -1 = -12 int numberOfMonthsBetweenYears = INT_TotalMonthsInAYear * yearsApart; return numberOfMonthsBetweenYears; } private static int getAbsMonthsApartMinusOne( DateTime startDate, DateTime finishDate, int numberOfMonthsBetweenStartAndFinishYears ) { // This may be negative ie 7 - 9 = -2 int numberOfMonthsBetweenStartAndFinishMonths = startDate.Month - finishDate.Month; // Absolute Value Of Total Months In Years Plus The Simple Months Difference Which May Be Negative So We Use Abs Function int absDiffInMonths = Math.Abs( numberOfMonthsBetweenStartAndFinishYears + numberOfMonthsBetweenStartAndFinishMonths ); // Subtract one here because we are going to use a perecentage difference based on the number of days left in the start month // and adding together the number of days that we've made it so far in the finish month. int absMonthsApartMinusOne = absDiffInMonths - 1; return absMonthsApartMinusOne; } /// <summary> /// For example for 7/8/2012 there are 24 days left in the month so about .77 percentage of month is left. /// </summary> private static decimal getDaysLeftToCompleteInStartMonthPercentage( DateTime startDate ) { // startDate = "7/8/2012" // 31 decimal daysInStartMonth = DateTime.DaysInMonth( startDate.Year, startDate.Month ); // 31 - 8 = 23 decimal totalDaysInStartMonthMinusStartDay = daysInStartMonth - startDate.Day; // add one to mark the day as being completed. 23 + 1 = 24 decimal daysLeftInStartMonth = totalDaysInStartMonthMinusStartDay + 1; // 24 / 31 = .77 days left to go in the month decimal daysLeftToCompleteInStartMonthPercentage = daysLeftInStartMonth / daysInStartMonth; return daysLeftToCompleteInStartMonthPercentage; } /// <summary> /// For example if the finish date were 9/8/2012 we've completed 8 days so far or .24 percent of the month /// </summary> private static decimal getDaysCompletedSoFarInFinishMonthPercentage( DateTime finishDate ) { // for septebmer = 30 days in month. decimal daysInFinishMonth = DateTime.DaysInMonth( finishDate.Year, finishDate.Month ); // 8 days divided by 30 = .26 days completed so far in finish month. decimal daysCompletedSoFarInFinishMonthPercentage = finishDate.Day / daysInFinishMonth; return daysCompletedSoFarInFinishMonthPercentage; } 
0
source share

This solution calculates whole months, and then adds a partial month depending on the end of the time period. Thus, it always calculates the full months between the day-month dates, and then calculates the incomplete month depending on the number of days left.

 public decimal getMonthDiff(DateTime date1, DateTime date2) { // Make parameters agnostic var earlyDate = (date1 < date2 ? date1 : date2); var laterDate = (date1 > date2 ? date1 : date2); // Calculate the change in full months decimal months = ((laterDate.Year - earlyDate.Year) * 12) + (laterDate.Month - earlyDate.Month) - 1; // Add partial months based on the later date if (earlyDate.Day <= laterDate.Day) { decimal laterMonthDays = DateTime.DaysInMonth(laterDate.Year, laterDate.Month); decimal laterPartialMonth = ((laterDate.Day - earlyDate.Day) / laterMonthDays); months += laterPartialMonth + 1; } else { var laterLastMonth = laterDate.AddMonths(-1); decimal laterLastMonthDays = DateTime.DaysInMonth(laterLastMonth.Year, laterLastMonth.Month); decimal laterPartialMonth = ((laterLastMonthDays - earlyDate.Day + laterDate.Day) / laterLastMonthDays); months += laterPartialMonth; } return months; } 
0
source share

Below is the calculation according to which the Dutch tax office wants to calculate the months. This means that when the starting day, for example, February 22, march 23 should be the result of something above 1, and not just something like 0.98.

  private decimal GetMonthDiffBetter(DateTime date1, DateTime date2) { DateTime start = date1 < date2 ? date1 : date2; DateTime end = date1 < date2 ? date2 : date1; int totalYearMonths = (end.Year - start.Year) * 12; int restMonths = end.Month - start.Month; int totalMonths = totalYearMonths + restMonths; decimal monthPart = (decimal)end.Day / (decimal)start.Day; return totalMonths - 1 + monthPart; }` 
0
source share

This should lead you where you need to:

 DateTime start = new DateTime(2001, 1, 1); DateTime finish = new DateTime(2002, 3, 15); double diff = (finish - start).TotalDays / 30; 
-one
source share

a framework as a TimeSpan object, which is the result of subtracting two dates.

Subtraction is already considering various February options (28/29 days per month), so in my opinion, this is the best practice after you received it, you can format it as you like.

  DateTime dates1 = new DateTime(2010, 1, 1); DateTime dates2 = new DateTime(2010, 3, 15); var span = dates1.Subtract(dates2); span.ToString("your format here"); 
-one
source share
  private Double GetTotalMonths(DateTime future, DateTime past) { Double totalMonths = 0.0; while ((future - past).TotalDays > 28 ) { past = past.AddMonths(1); totalMonths += 1; } var daysInCurrent = DateTime.DaysInMonth(future.Year, future.Month); var remaining = future.Day - past.Day; totalMonths += ((Double)remaining / (Double)daysInCurrent); return totalMonths; } 
-one
source share

All Articles