Diferencia en meses entre dos fechas

¿Cómo calcular la diferencia en meses entre dos fechas en C #?

¿Hay un equivalente del método DateDiff() de VB en C #. Necesito encontrar la diferencia en meses entre dos fechas que están separadas por años. La documentación dice que puedo usar TimeSpan como:

 TimeSpan ts = date1 - date2; 

pero esto me da datos en Días. No quiero dividir este número entre 30 porque no todos los meses son 30 días y dado que los dos valores de operando están bastante separados uno del otro, me temo que dividir por 30 podría darme un valor incorrecto.

¿Alguna sugerencia?

Suponiendo que el día del mes es irrelevante (es decir, la diferencia entre 2011.1.1 y 2010.12.31 es 1), con date1> date2 dando un valor positivo y date2> date1 un valor negativo

 ((date1.Year - date2.Year) * 12) + date1.Month - date2.Month 

O bien, suponiendo que desee una cantidad aproximada de “meses promedio” entre las dos fechas, lo siguiente debería funcionar para todas las diferencias de fechas pero muy grandes.

 date1.Subtract(date2).Days / (365.25 / 12) 

Tenga en cuenta que si utilizara la última solución, las pruebas de su unidad deberían indicar el rango de fechas más amplio para el que está diseñada su aplicación y validar los resultados del cálculo en consecuencia.


Actualización (gracias a Gary )

Si usa el método de “meses promedio”, un número un poco más preciso para usar para el “promedio de días por año” es 365.2425 .

Aquí hay una solución integral para devolver un DateTimeSpan , similar a un TimeSpan , excepto que incluye todos los componentes de fecha además de los componentes de tiempo.

Uso:

 void Main() { DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM"); DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM"); var dateSpan = DateTimeSpan.CompareDates(compareTo, now); Console.WriteLine("Years: " + dateSpan.Years); Console.WriteLine("Months: " + dateSpan.Months); Console.WriteLine("Days: " + dateSpan.Days); Console.WriteLine("Hours: " + dateSpan.Hours); Console.WriteLine("Minutes: " + dateSpan.Minutes); Console.WriteLine("Seconds: " + dateSpan.Seconds); Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds); } 

Productos:

Años: 1
Meses: 5
Días: 27
Horas: 1
Minutos: 36
Segundos: 50
Milisegundos: 0

Para mayor comodidad, he agrupado la lógica en la estructura DateTimeSpan , pero puede mover el método CompareDates donde lo considere oportuno. También tenga en cuenta que no importa qué fecha viene antes que la otra.

 public struct DateTimeSpan { private readonly int years; private readonly int months; private readonly int days; private readonly int hours; private readonly int minutes; private readonly int seconds; private readonly int milliseconds; public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds) { this.years = years; this.months = months; this.days = days; this.hours = hours; this.minutes = minutes; this.seconds = seconds; this.milliseconds = milliseconds; } public int Years { get { return years; } } public int Months { get { return months; } } public int Days { get { return days; } } public int Hours { get { return hours; } } public int Minutes { get { return minutes; } } public int Seconds { get { return seconds; } } public int Milliseconds { get { return milliseconds; } } enum Phase { Years, Months, Days, Done } public static DateTimeSpan CompareDates(DateTime date1, DateTime date2) { if (date2 < date1) { var sub = date1; date1 = date2; date2 = sub; } DateTime current = date1; int years = 0; int months = 0; int days = 0; Phase phase = Phase.Years; DateTimeSpan span = new DateTimeSpan(); int officialDay = current.Day; while (phase != Phase.Done) { switch (phase) { case Phase.Years: if (current.AddYears(years + 1) > date2) { phase = Phase.Months; current = current.AddYears(years); } else { years++; } break; case Phase.Months: if (current.AddMonths(months + 1) > date2) { phase = Phase.Days; current = current.AddMonths(months); if (current.Day < officialDay && officialDay <= DateTime.DaysInMonth(current.Year, current.Month)) current = current.AddDays(officialDay - current.Day); } else { months++; } break; case Phase.Days: if (current.AddDays(days + 1) > date2) { current = current.AddDays(days); var timespan = date2 - current; span = new DateTimeSpan(years, months, days, timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds); phase = Phase.Done; } else { days++; } break; } } return span; } } 

Si desea el número exacto de meses completos, siempre positivo (2000-01-15, 2000-02-14 devuelve 0), considerando un mes completo es cuando alcanza el mismo día del mes siguiente (algo así como el cálculo de la edad)

 public static int GetMonthsBetween(DateTime from, DateTime to) { if (from > to) return GetMonthsBetween(to, from); var monthDiff = Math.Abs((to.Year * 12 + (to.Month - 1)) - (from.Year * 12 + (from.Month - 1))); if (from.AddMonths(monthDiff) > to || to.Day < from.Day) { return monthDiff - 1; } else { return monthDiff; } } 

Razón de edición: el código anterior no era correcto en algunos casos, como:

 new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 }, Test cases I used to test the function: var tests = new[] { new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 1), Result = 0 }, new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 2), Result = 0 }, new { From = new DateTime(1900, 1, 2), To = new DateTime(1900, 1, 1), Result = 0 }, new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 2, 1), Result = 1 }, new { From = new DateTime(1900, 2, 1), To = new DateTime(1900, 1, 1), Result = 1 }, new { From = new DateTime(1900, 1, 31), To = new DateTime(1900, 2, 1), Result = 0 }, new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 9, 30), Result = 0 }, new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 10, 1), Result = 1 }, new { From = new DateTime(1900, 1, 1), To = new DateTime(1901, 1, 1), Result = 12 }, new { From = new DateTime(1900, 1, 1), To = new DateTime(1911, 1, 1), Result = 132 }, new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 }, }; 

Podrías hacerlo

 if ( date1.AddMonths(x) > date2 ) 

Comprobé el uso de este método en VB.NET a través de MSDN y parece que tiene muchos usos. No hay tal método incorporado en C #. (Incluso no es una buena idea) puede llamar a VB en C #.

  1. Agregue Microsoft.VisualBasic.dll a su proyecto como referencia
  2. use Microsoft.VisualBasic.DateAndTime.DateDiff en su código

Para obtener la diferencia en meses (tanto de inicio como de finalización), independientemente de las fechas:

 DateTime start = new DateTime(2013, 1, 1); DateTime end = new DateTime(2014, 2, 1); var diffMonths = (end.Month + end.Year * 12) - (start.Month + start.Year * 12); 

Solo necesitaba algo sencillo de atender, por ejemplo, las fechas de empleo donde solo se ingresa el mes / año, por lo que quería años y meses distintos de trabajo. Esto es lo que uso, aquí solo para la utilidad.

 public static YearsMonths YearMonthDiff(DateTime startDate, DateTime endDate) { int monthDiff = ((endDate.Year * 12) + endDate.Month) - ((startDate.Year * 12) + startDate.Month) + 1; int years = (int)Math.Floor((decimal) (monthDiff / 12)); int months = monthDiff % 12; return new YearsMonths { TotalMonths = monthDiff, Years = years, Months = months }; } 

.NET Fiddle

Puede usar la clase DateDiff de la Biblioteca de períodos de tiempo para .NET :

 // ---------------------------------------------------------------------- public void DateDiffSample() { DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 ); DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 ); DateDiff dateDiff = new DateDiff( date1, date2 ); // differences Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months ); // > DateDiff.Months: 16 // elapsed Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths ); // > DateDiff.ElapsedMonths: 4 // description Console.WriteLine( "DateDiff.GetDescription(6): {0}", dateDiff.GetDescription( 6 ) ); // > DateDiff.GetDescription(6): 1 Year 4 Months 12 Days 12 Hours 41 Mins 29 Secs } // DateDiffSample 

Use Noda Time :

 LocalDate start = new LocalDate(2013, 1, 5); LocalDate end = new LocalDate(2014, 6, 1); Period period = Period.Between(start, end, PeriodUnits.Months); Console.WriteLine(period.Months); // 16 

(fuente de ejemplo)

Esto funcionó para lo que necesitaba. El día del mes no importaba en mi caso porque siempre es el último día del mes.

 public static int MonthDiff(DateTime d1, DateTime d2){ int retVal = 0; if (d1.Month 

La forma más precisa es esta que devuelve la diferencia en meses por fracción:

 private double ReturnDiffereceBetweenTwoDatesInMonths(DateTime startDateTime, DateTime endDateTime) { double result = 0; double days = 0; DateTime currentDateTime = startDateTime; while (endDateTime > currentDateTime.AddMonths(1)) { result ++; currentDateTime = currentDateTime.AddMonths(1); } if (endDateTime > currentDateTime) { days = endDateTime.Subtract(currentDateTime).TotalDays; } return result + days/endDateTime.GetMonthDays; } 

Aquí hay una solución simple que funciona al menos para mí. Sin embargo, probablemente no sea el más rápido porque utiliza la función AddMonth de DateTime en un bucle:

 public static int GetMonthsDiff(DateTime start, DateTime end) { if (start > end) return GetMonthsDiff(end, start); int months = 0; do { start = start.AddMonths(1); if (start > end) return months; months++; } while (true); } 
 Public Class ClassDateOperation Private prop_DifferenceInDay As Integer Private prop_DifferenceInMonth As Integer Private prop_DifferenceInYear As Integer Public Function DayMonthYearFromTwoDate(ByVal DateStart As Date, ByVal DateEnd As Date) As ClassDateOperation Dim differenceInDay As Integer Dim differenceInMonth As Integer Dim differenceInYear As Integer Dim myDate As Date DateEnd = DateEnd.AddDays(1) differenceInYear = DateEnd.Year - DateStart.Year If DateStart.Month <= DateEnd.Month Then differenceInMonth = DateEnd.Month - DateStart.Month Else differenceInYear -= 1 differenceInMonth = (12 - DateStart.Month) + DateEnd.Month End If If DateStart.Day <= DateEnd.Day Then differenceInDay = DateEnd.Day - DateStart.Day Else myDate = CDate("01/" & DateStart.AddMonths(1).Month & "/" & DateStart.Year).AddDays(-1) If differenceInMonth <> 0 Then differenceInMonth -= 1 Else differenceInMonth = 11 differenceInYear -= 1 End If differenceInDay = myDate.Day - DateStart.Day + DateEnd.Day End If prop_DifferenceInDay = differenceInDay prop_DifferenceInMonth = differenceInMonth prop_DifferenceInYear = differenceInYear Return Me End Function Public ReadOnly Property DifferenceInDay() As Integer Get Return prop_DifferenceInDay End Get End Property Public ReadOnly Property DifferenceInMonth As Integer Get Return prop_DifferenceInMonth End Get End Property Public ReadOnly Property DifferenceInYear As Integer Get Return prop_DifferenceInYear End Get End Property End Class 

Esto es de mi propia biblioteca, devolverá la diferencia de meses entre dos fechas.

 public static int MonthDiff(DateTime d1, DateTime d2) { int retVal = 0; // Calculate the number of years represented and multiply by 12 // Substract the month number from the total // Substract the difference of the second month and 12 from the total retVal = (d1.Year - d2.Year) * 12; retVal = retVal - d1.Month; retVal = retVal - (12 - d2.Month); return retVal; } 

Puedes tener una función como esta.

Por ejemplo, desde 2012/12/27 hasta 2012/12/29 se convierte en 3 días. Del mismo modo, desde el 12/12/2012 hasta el 13/01/2013 se convierte en 2 meses, porque hasta el 14/01/2013 es de 1 mes. desde el 15, comenzó el segundo mes.

Puede eliminar “=” en la segunda condición if si no desea incluir ambos días en el cálculo. es decir, desde 2012/12/15 hasta 2013/01/15 es 1 mes.

 public int GetMonths(DateTime startDate, DateTime endDate) { if (startDate > endDate) { throw new Exception("Start Date is greater than the End Date"); } int months = ((endDate.Year * 12) + endDate.Month) - ((startDate.Year * 12) + startDate.Month); if (endDate.Day >= startDate.Day) { months++; } return months; } 

puede usar la siguiente extensión: Código

 public static class Ext { #region Public Methods public static int GetAge(this DateTime @this) { var today = DateTime.Today; return ((((today.Year - @this.Year) * 100) + (today.Month - @this.Month)) * 100 + today.Day - @this.Day) / 10000; } public static int DiffMonths(this DateTime @from, DateTime @to) { return (((((@to.Year - @from.Year) * 12) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 100); } public static int DiffYears(this DateTime @from, DateTime @to) { return ((((@to.Year - @from.Year) * 100) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 10000; } #endregion Public Methods } 

Implementación!

 int Age; int years; int Months; //Replace your own date var d1 = new DateTime(2000, 10, 22); var d2 = new DateTime(2003, 10, 20); //Age Age = d1.GetAge(); Age = d2.GetAge(); //positive years = d1.DiffYears(d2); Months = d1.DiffMonths(d2); //negative years = d2.DiffYears(d1); Months = d2.DiffMonths(d1); //Or Months = Ext.DiffMonths(d1, d2); years = Ext.DiffYears(d1, d2); 

Aquí hay una solución mucho más concisa usando VB.Net DateDiff solo para el año, el mes y el día. También puede cargar la biblioteca DateDiff en C #.

date1 debe ser <= date2

VB.NET

 Dim date1 = Now.AddDays(-2000) Dim date2 = Now Dim diffYears = DateDiff(DateInterval.Year, date1, date2) - If(date1.DayOfYear > date2.DayOfYear, 1, 0) Dim diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - If(date1.Day > date2.Day, 1, 0) Dim diffDays = If(date2.Day >= date1.Day, date2.Day - date1.Day, date2.Day + (Date.DaysInMonth(date1.Year, date1.Month) - date1.Day)) 

DO#

 DateTime date1 = Now.AddDays(-2000); DateTime date2 = Now; int diffYears = DateDiff(DateInterval.Year, date1, date2) - date1.DayOfYear > date2.DayOfYear ? 1 : 0; int diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - date1.Day > date2.Day ? 1 : 0; int diffDays = date2.Day >= date1.Day ? date2.Day - date1.Day : date2.Day + (System.DateTime.DaysInMonth(date1.Year, date1.Month) - date1.Day); 

Aquí está mi contribución para obtener la diferencia en los meses que he encontrado que son precisos:

 namespace System { public static class DateTimeExtensions { public static Int32 DiffMonths( this DateTime start, DateTime end ) { Int32 months = 0; DateTime tmp = start; while ( tmp < end ) { months++; tmp = tmp.AddMonths( 1 ); } return months; } } } 

Uso:

 Int32 months = DateTime.Now.DiffMonths( DateTime.Now.AddYears( 5 ) ); 

Puede crear otro método llamado DiffYears y aplicar exactamente la misma lógica que la anterior y AddYears en lugar de AddMonths en el ciclo while.

Esto es en respuesta a la respuesta de Kirk Woll. Aún no tengo suficientes puntos de reputación para responder a un comentario …

Me gustó la solución de Kirk y la iba a arrancar desvergonzadamente y usarla en mi código, pero cuando lo miré, me di cuenta de que era demasiado complicado. Conmutación y bucle innecesarios, y un constructor público que no tiene sentido utilizar.

Aquí está mi reescritura:

 public class DateTimeSpan { private DateTime _date1; private DateTime _date2; private int _years; private int _months; private int _days; private int _hours; private int _minutes; private int _seconds; private int _milliseconds; public int Years { get { return _years; } } public int Months { get { return _months; } } public int Days { get { return _days; } } public int Hours { get { return _hours; } } public int Minutes { get { return _minutes; } } public int Seconds { get { return _seconds; } } public int Milliseconds { get { return _milliseconds; } } public DateTimeSpan(DateTime date1, DateTime date2) { _date1 = (date1 > date2) ? date1 : date2; _date2 = (date2 < date1) ? date2 : date1; _years = _date1.Year - _date2.Year; _months = (_years * 12) + _date1.Month - _date2.Month; TimeSpan t = (_date2 - _date1); _days = t.Days; _hours = t.Hours; _minutes = t.Minutes; _seconds = t.Seconds; _milliseconds = t.Milliseconds; } public static DateTimeSpan CompareDates(DateTime date1, DateTime date2) { return new DateTimeSpan(date1, date2); } } 

Usage1, más o menos lo mismo:

 void Main() { DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM"); DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM"); var dateSpan = new DateTimeSpan(compareTo, now); Console.WriteLine("Years: " + dateSpan.Years); Console.WriteLine("Months: " + dateSpan.Months); Console.WriteLine("Days: " + dateSpan.Days); Console.WriteLine("Hours: " + dateSpan.Hours); Console.WriteLine("Minutes: " + dateSpan.Minutes); Console.WriteLine("Seconds: " + dateSpan.Seconds); Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds); } 

Usage2, similar:

 void Main() { DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM"); DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM"); Console.WriteLine("Years: " + DateTimeSpan.CompareDates(compareTo, now).Years); Console.WriteLine("Months: " + DateTimeSpan.CompareDates(compareTo, now).Months); Console.WriteLine("Days: " + DateTimeSpan.CompareDates(compareTo, now).Days); Console.WriteLine("Hours: " + DateTimeSpan.CompareDates(compareTo, now).Hours); Console.WriteLine("Minutes: " + DateTimeSpan.CompareDates(compareTo, now).Minutes); Console.WriteLine("Seconds: " + DateTimeSpan.CompareDates(compareTo, now).Seconds); Console.WriteLine("Milliseconds: " + DateTimeSpan.CompareDates(compareTo, now).Milliseconds); } 

En mi caso, se requiere calcular el mes completo desde la fecha de inicio hasta el día anterior a este día del mes siguiente o desde el inicio hasta el final del mes.

Ej: del 1/1/2018 al 31/1/2018 es un mes completo
Ex2: del 5/1/2018 al 4/2/2018 es un mes completo

así que basado en esto aquí está mi solución:

 public static DateTime GetMonthEnd(DateTime StartDate, int MonthsCount = 1) { return StartDate.AddMonths(MonthsCount).AddDays(-1); } public static Tuple CalcPeriod(DateTime StartDate, DateTime EndDate) { int MonthsCount = 0; Tuple Period; while (true) { if (GetMonthEnd(StartDate) > EndDate) break; else { MonthsCount += 1; StartDate = StartDate.AddMonths(1); } } int RemainingDays = (EndDate - StartDate).Days + 1; Period = new Tuple(MonthsCount, RemainingDays); return Period; } 

Uso:

 Tuple Period = CalcPeriod(FromDate, ToDate); 

Nota: en mi caso fue necesario calcular los días restantes después de los meses completos, de modo que si no es tu caso, podrías ignorar el resultado del día o incluso podrías cambiar el retorno del método de tupla a entero.

 public static int PayableMonthsInDuration(DateTime StartDate, DateTime EndDate) { int sy = StartDate.Year; int sm = StartDate.Month; int count = 0; do { count++;if ((sy == EndDate.Year) && (sm >= EndDate.Month)) { break; } sm++;if (sm == 13) { sm = 1; sy++; } } while ((EndDate.Year >= sy) || (EndDate.Month >= sm)); return (count); } 

Esta solución es para el cálculo de alquiler / suscripción, donde la diferencia no significa que sea una resta, sino el intervalo dentro de esas dos fechas.

Hay 3 casos: el mismo año, el año anterior y otros años.

Si el día del mes no importa …

 public int GetTotalNumberOfMonths(DateTime start, DateTime end) { // work with dates in the right order if (start > end) { var swapper = start; start = end; end = swapper; } switch (end.Year - start.Year) { case 0: // Same year return end.Month - start.Month; case 1: // last year return (12 - start.Month) + end.Month; default: return 12 * (3 - (end.Year - start.Year)) + (12 - start.Month) + end.Month; } } 

Escribí una función para lograr esto, porque las otras formas no me funcionaban.

 public string getEndDate (DateTime startDate,decimal monthCount) { int y = startDate.Year; int m = startDate.Month; for (decimal i = monthCount; i > 1; i--) { m++; if (m == 12) { y++; m = 1; } } return string.Format("{0}-{1}-{2}", y.ToString(), m.ToString(), startDate.Day.ToString()); } 

Mi comprensión de la diferencia total de meses entre 2 fechas tiene una parte integral y una parte fraccional (la fecha importa).

La parte integral es la diferencia de meses completos.

La parte fraccionaria, para mí, es la diferencia del% del día (a los días completos del mes) entre los meses inicial y final.

 public static class DateTimeExtensions { public static double TotalMonthsDifference(this DateTime from, DateTime to) { //Compute full months difference between dates var fullMonthsDiff = (to.Year - from.Year)*12 + to.Month - from.Month; //Compute difference between the % of day to full days of each month var fractionMonthsDiff = ((double)(to.Day-1) / (DateTime.DaysInMonth(to.Year, to.Month)-1)) - ((double)(from.Day-1)/ (DateTime.DaysInMonth(from.Year, from.Month)-1)); return fullMonthsDiff + fractionMonthsDiff; } } 

Con esta extensión, esos son los resultados:

 2/29/2000 TotalMonthsDifference 2/28/2001 => 12 2/28/2000 TotalMonthsDifference 2/28/2001 => 12.035714285714286 01/01/2000 TotalMonthsDifference 01/16/2000 => 0.5 01/31/2000 TotalMonthsDifference 01/01/2000 => -1.0 01/31/2000 TotalMonthsDifference 02/29/2000 => 1.0 01/31/2000 TotalMonthsDifference 02/28/2000 => 0.9642857142857143 01/31/2001 TotalMonthsDifference 02/28/2001 => 1.0 

There are not a lot of clear answers on this because you are always assuming things.

This solution calculates between two dates the months between assuming you want to save the day of month for comparison, (meaning that the day of the month is considered in the calculation)

Example, if you have a date of 30 Jan 2012, 29 Feb 2012 will not be a month but 01 March 2013 will.

It’s been tested pretty thoroughly, probably will clean it up later as we use it, but here:

 private static int TotalMonthDifference(DateTime dtThis, DateTime dtOther) { int intReturn = 0; bool sameMonth = false; if (dtOther.Date < dtThis.Date) //used for an error catch in program, returns -1 intReturn--; int dayOfMonth = dtThis.Day; //captures the month of day for when it adds a month and doesn't have that many days int daysinMonth = 0; //used to caputre how many days are in the month while (dtOther.Date > dtThis.Date) //while Other date is still under the other { dtThis = dtThis.AddMonths(1); //as we loop, we just keep adding a month for testing daysinMonth = DateTime.DaysInMonth(dtThis.Year, dtThis.Month); //grabs the days in the current tested month if (dtThis.Day != dayOfMonth) //Example 30 Jan 2013 will go to 28 Feb when a month is added, so when it goes to march it will be 28th and not 30th { if (daysinMonth < dayOfMonth) // uses day in month max if can't set back to day of month dtThis.AddDays(daysinMonth - dtThis.Day); else dtThis.AddDays(dayOfMonth - dtThis.Day); } if (((dtOther.Year == dtThis.Year) && (dtOther.Month == dtThis.Month))) //If the loop puts it in the same month and year { if (dtOther.Day >= dayOfMonth) //check to see if it is the same day or later to add one to month intReturn++; sameMonth = true; //sets this to cancel out of the normal counting of month } if ((!sameMonth)&&(dtOther.Date > dtThis.Date))//so as long as it didn't reach the same month (or if i started in the same month, one month ahead, add a month) intReturn++; } return intReturn; //return month } 

To be able to calculate the difference between 2 dates in months is a perfectly logical thing to do, and is needed in many business applications. The several coders here who have provided comments such as – what’s the difference in months between “May 1,2010” and “June 16,2010, what’s the difference in months between 31 December 2010 and 1 Jan 2011? — have failed to understand the very basics of business applications.

Here is the answer to the above 2 comments – The number of months between 1-may-2010 and 16-jun-2010 is 1 month, the number of months between 31-dec-2010 and 1-jan-2011 is 0. It would be very foolish to calculate them as 1.5 months and 1 second, as the coders above have suggested.

People who have worked on credit card, mortgage processing, tax processing, rent processing, monthly interest calculations and a vast variety of other business solutions would agree.

Problem is that such a function is not included in C# or VB.NET for that matter. Datediff only takes into account years or the month component, so is actually useless.

Here are some real-life examples of where you need to and correctly can calculate months:

You lived in a short-term rental from 18-feb to 23-aug. How many months did you stay there? The answer is a simple – 6 months

You have a bank acount where interest is calculated and paid at the end of every month. You deposit money on 10-jun and take it out 29-oct (same year). How many months do you get interest for? Very simple answer- 4 months (again the extra days do not matter)

In business applications, most of the time, when you need to calculate months, it is because you need to know ‘full’ months based on how humans calculate time; not based on some abstract/irrelevant thoughts.

Expanded Kirks struct with ToString(format) and Duration(long ms)

  public struct DateTimeSpan { private readonly int years; private readonly int months; private readonly int days; private readonly int hours; private readonly int minutes; private readonly int seconds; private readonly int milliseconds; public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds) { this.years = years; this.months = months; this.days = days; this.hours = hours; this.minutes = minutes; this.seconds = seconds; this.milliseconds = milliseconds; } public int Years { get { return years; } } public int Months { get { return months; } } public int Days { get { return days; } } public int Hours { get { return hours; } } public int Minutes { get { return minutes; } } public int Seconds { get { return seconds; } } public int Milliseconds { get { return milliseconds; } } enum Phase { Years, Months, Days, Done } public string ToString(string format) { format = format.Replace("YYYY", Years.ToString()); format = format.Replace("MM", Months.ToString()); format = format.Replace("DD", Days.ToString()); format = format.Replace("hh", Hours.ToString()); format = format.Replace("mm", Minutes.ToString()); format = format.Replace("ss", Seconds.ToString()); format = format.Replace("ms", Milliseconds.ToString()); return format; } public static DateTimeSpan Duration(long ms) { DateTime dt = new DateTime(); return CompareDates(dt, dt.AddMilliseconds(ms)); } public static DateTimeSpan CompareDates(DateTime date1, DateTime date2) { if (date2 < date1) { var sub = date1; date1 = date2; date2 = sub; } DateTime current = date1; int years = 0; int months = 0; int days = 0; Phase phase = Phase.Years; DateTimeSpan span = new DateTimeSpan(); while (phase != Phase.Done) { switch (phase) { case Phase.Years: if (current.AddYears(years + 1) > date2) { phase = Phase.Months; current = current.AddYears(years); } else { years++; } break; case Phase.Months: if (current.AddMonths(months + 1) > date2) { phase = Phase.Days; current = current.AddMonths(months); } else { months++; } break; case Phase.Days: if (current.AddDays(days + 1) > date2) { current = current.AddDays(days); var timespan = date2 - current; span = new DateTimeSpan(years, months, days, timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds); phase = Phase.Done; } else { days++; } break; } } return span; } } 
  var dt1 = (DateTime.Now.Year * 12) + DateTime.Now.Month; var dt2 = (DateTime.Now.AddMonths(-13).Year * 12) + DateTime.Now.AddMonths(-13).Month; Console.WriteLine(dt1); Console.WriteLine(dt2); Console.WriteLine((dt1 - dt2)); 

Here’s how we approach this:

 public static int MonthDiff(DateTime date1, DateTime date2) { if (date1.Month < date2.Month) { return (date2.Year - date1.Year) * 12 + date2.Month - date1.Month; } else { return (date2.Year - date1.Year - 1) * 12 + date2.Month - date1.Month + 12; } } 
 int nMonths = 0; if (FDate.ToDateTime().Year == TDate.ToDateTime().Year) nMonths = TDate.ToDateTime().Month - FDate.ToDateTime().Month; else nMonths = (12 - FDate.Month) + TDate.Month;