Разница в месяцах между двумя датами
как посчитать разницу в месяцах между двумя датами в C#?
есть эквивалент vb's DateDiff()
метод в C#. Мне нужно найти разницу в месяцах между двумя датами, которые разделяют годы. В документации говорится, что я могу использовать TimeSpan
как:
TimeSpan ts = date1 - date2;
но это дает мне данных дней. Я не хочу делить это число на 30 потому что не каждый месяц составляет 30 дней, и так как два значения операнда довольно далеки друг от друга, я боюсь, деление на 30 может дать мне неправильное значение.
какие предложения?
30 ответов
предполагая, что день месяца не имеет значения (т. е. разница между 2011.1.1 и 2010.12.31 равна 1), с date1 > date2 дает положительное значение и date2 > date1 отрицательное значение
((date1.Year - date2.Year) * 12) + date1.Month - date2.Month
или, предполагая, что вы хотите приблизительное количество "средних месяцев" между двумя датами, следующее должно работать для всех, кроме очень больших различий в датах.
date1.Subtract(date2).Days / (365.25 / 12)
Примечание, Если вы должны были использовать последнее решение, то ваши модульные тесты должны указать самый широкий диапазон дат с которым ваше приложение предназначено для работы и проверки результатов расчета соответственно.
обновление (благодаря Гари)
при использовании метода "средние месяцы" несколько более точное число для использования "среднее количество дней в году" -365.2425.
вот комплексное решение для возврата DateTimeSpan
, похожий на TimeSpan
, за исключением того, что она включает в себя все компоненты даты в дополнение к компонентам время.
использование:
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);
}
выходы:
лет: 1
Месяцев: 5
Дней: 27
Часов: 1
Минут: 36
Секунд: 50
МС: 0
для удобства я свалил логику в DateTimeSpan
структура, но вы можете переместить метод CompareDates
там, где вы считаете нужным. Также обратите внимание,что не имеет значения, какая дата предшествует другой.
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;
}
}
Если вы хотите точное количество полных месяцев, всегда положительно (2000-01-15, 2000-02-14 возвращает 0), учитывая, что полный месяц, когда вы достигнете того же дня в следующем месяце (что-то вроде расчета возраста)
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;
}
}
изменить причину: старый код не был правильным в некоторых случаях, таких как:
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 },
};
Я проверил использование этого метода в VB.NET через MSDN и кажется, что у него много обычаев. В C#нет такого встроенного метода. (Даже это не очень хорошая идея) вы можете позвонить VB в C#.
- добавить
Microsoft.VisualBasic.dll
to ваш проект в качестве ссылки - использовать
Microsoft.VisualBasic.DateAndTime.DateDiff
в вашем коде
чтобы получить разницу в месяцах (как начало, так и конец включительно), независимо от дат:
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);
Мне просто нужно было что-то простое, чтобы удовлетворить, например, даты занятости, где вводится только месяц/год, поэтому хотелось, чтобы разные годы и месяцы работали. Это то, что я использую, здесь только для пользы
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
};
}
можно использовать функция datediff класс период времени библиотеки .Чистая:
// ----------------------------------------------------------------------
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
использовать Нода Времени:
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
это сработало для того, для чего мне это было нужно. День месяца в моем случае не имел значения, потому что это всегда последний день месяца.
public static int MonthDiff(DateTime d1, DateTime d2){
int retVal = 0;
if (d1.Month<d2.Month)
{
retVal = (d1.Month + 12) - d2.Month;
retVal += ((d1.Year - 1) - d2.Year)*12;
}
else
{
retVal = d1.Month - d2.Month;
retVal += (d1.Year - d2.Year)*12;
}
//// 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;
}
Наиболее точным способом является то, что разница возврата в месяцах по дробям:
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;
}
вот простое решение, которое работает, по крайней мере для меня. Это, вероятно, не самый быстрый, потому что он использует функцию AddMonth прохладного DateTime в цикле:
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
Это из моей собственной библиотеки, вернет разницу месяцев между двумя датами.
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;
}
у вас может быть функция что-то вроде этого.
например, с 2012/12/27 по 2012/12/29 становится 3 дня. Аналогично, с 2012/12/15 до 2013/01/15 становится 2 месяца, потому что до 2013/01/14 это 1 месяц. с 15-го начался 2-й месяц.
вы можете удалить " = " во втором условии if, если вы не хотите включать оба дня в расчет. я.е с 2012/12/15 в 2013/01/15-1 месяц.
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;
}
вы можете использовать следующие расширения: код
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
}
реализация !
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);
вот гораздо более краткое решение с использованием VB.Net DateDiff только для года, месяца, дня. Вы также можете загрузить библиотеку DateDiff в C#.
date1 должно быть
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))
C#
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);
вот мой вклад, чтобы получить разницу в месяцах, которые я нашел, чтобы быть точным:
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;
}
}
}
использование:
Int32 months = DateTime.Now.DiffMonths( DateTime.Now.AddYears( 5 ) );
вы можете создать другой метод под названием DiffYears и применить точно такую же логику, как выше, и AddYears вместо AddMonths в цикле while.
Это в ответ на ответ Кирка волла. У меня пока недостаточно очков репутации, чтобы ответить на комментарий...
мне понравилось решение Кирка и я собирался бесстыдно сорвать его и использовать в своем коде, но когда я просмотрел его, я понял, что это слишком сложно. Ненужное переключение и цикл, а также общедоступный конструктор, который бессмысленно использовать.
вот мой рерайт:
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, в значительной степени то же самое:
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, похожие:
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);
}
в моем случае требуется рассчитать полный месяц от даты начала до дня, предшествующего этому дню в следующем месяце или от начала до конца месяца.
Ex: от 1/1/2018 до 31/1/2018-это полный месяц
Ex2: от 5/1/2018 до 4/2/2018-это полный месяц
Итак, основываясь на этом, вот мое решение:
public static DateTime GetMonthEnd(DateTime StartDate, int MonthsCount = 1)
{
return StartDate.AddMonths(MonthsCount).AddDays(-1);
}
public static Tuple<int, int> CalcPeriod(DateTime StartDate, DateTime EndDate)
{
int MonthsCount = 0;
Tuple<int, int> Period;
while (true)
{
if (GetMonthEnd(StartDate) > EndDate)
break;
else
{
MonthsCount += 1;
StartDate = StartDate.AddMonths(1);
}
}
int RemainingDays = (EndDate - StartDate).Days + 1;
Period = new Tuple<int, int>(MonthsCount, RemainingDays);
return Period;
}
использование:
Tuple<int, int> Period = CalcPeriod(FromDate, ToDate);
Примечание: В моем случае потребовалось рассчитать оставшиеся дни после полные месяцы, поэтому, если это не ваш случай, вы можете игнорировать результат дней или даже изменить метод return от tuple до integer.
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);
}
Это решение предназначено для расчета аренды/подписки, где разница не означает вычитания, она должна быть промежутком в течение этих двух дат.
есть 3 случая: в тот же год, предыдущий год и другие годы.
Если день месяца, не важно...
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;
}
}
Я написал функцию для этого, потому что другие способы не работают для меня.
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());
}
мое понимание общей разницы месяцев между 2 датами имеет интегральную и дробную часть (дата имеет значение).
неотъемлемой частью является полная разница месяцев.
дробная часть для меня-это разница в % от дня (до полных дней месяца) между начальным и конечным месяцами.
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;
}
}
С этим расширением, таковы результаты:
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
на это не так много ясных ответов, потому что вы всегда предполагаете вещи.
это решение вычисляет между двумя датами месяцы между предполагая, что вы хотите сохранить день месяца для сравнения, (это означает, что день месяца рассматривается в расчете)
пример, если у вас есть дата 30 января 2012, 29 февраля 2012 не будет месяцем, но 01 марта 2013 будет.
Он был протестирован довольно тщательно, вероятно, очистит его позже, как мы его используем, но здесь:
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
}
чтобы иметь возможность рассчитать разницу между 2 датами в месяцах, это совершенно логично, и это необходимо во многих бизнес-приложениях. Несколько кодеров здесь, которые предоставили комментарии , такие как-какая разница в месяцах между "май 1,2010" и "июнь 16,2010, какая разница в месяцах между 31 декабря 2010 года и 1 января 2011 года? -- не смогли разобраться в самых основах бизнес-приложений.
вот ответ на вышеуказанные 2 комментария - Количество месяцев между 1 мая 2010 года и 16 июня 2010 года составляет 1 месяц, количество месяцев между 31 декабря 2010 года и 1 января 2011 года-0. Было бы очень глупо вычислять их как 1,5 месяца и 1 секунду, как предложили кодеры выше.
люди, которые работали на кредитной карте, ипотеки обработки, обработки налогов, аренды обработки, ежемесячные расчеты процентов и широкий спектр других бизнес-решений согласятся.
проблема в том, что такая функция не включено в C# или VB.NET если уж на то пошло. Datediff учитывает только годы или компонент месяца, поэтому на самом деле бесполезно.
вот некоторые реальные примеры того, где вам нужно и правильно рассчитать месяцы:
вы жили в краткосрочной аренде с 18 февраля по 23 августа. Сколько месяцев вы там пробыли? Ответ простой - 6 месяцев
У вас есть счет в банке, где проценты рассчитываются и выплачиваются в конце каждого месяца. Вы внесите деньги на 10 июня и выньте 29 октября (в том же году). На сколько месяцев вы получаете проценты? Очень простой ответ-4 месяца (опять же лишние дни не имеют значения)
в бизнес-приложениях большую часть времени, когда вам нужно рассчитать месяцы, это потому, что вам нужно знать "полные" месяцы, основанные на том, как люди вычисляют время; а не на некоторых абстрактных/нерелевантных мыслях.
Расширенная структура Киркса с ToString(format) и 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));
вот как мы подходим к этому:
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;