[C#] 두 날짜 사이의 월 차이 계산

C # /. NET TimeSpan에는 TotalDays, TotalMinutes등이 있지만 총 개월 차이에 대한 공식을 알 수는 없습니다. 한 달에 다양한 날과 윤년이 계속 저를 던져 버립니다. TotalMonths를 어떻게받을 수 있습니까 ?

편집 더 명확하지 않은 것에 대해 죄송합니다 : 실제로 이것을 얻을 수는 TimeSpan없지만 사용 TotalDays하고 있다고 생각 TotalMinutes하고 총 달을 얻는 것을 제외하고는 내가 찾고있는 것을 표현하는 좋은 예가 될 것입니다 …

예 : 2009 년 12 월 25 일-2009 년 10 월 6 일 = 총 2 개월 10 월 6 일부터 11 월 5 일까지는 0 개월입니다. 11 월 6 일, 1 개월 2 개월 12 월 6 일



답변

TimeSpan“월”은 가변 측정 단위이므로을 ( 를) 얻을 수 없습니다 . 직접 계산해야하며 작동 방식을 정확히 파악해야합니다.

예를 들어, 날짜 좋아해야 July 5, 2009하고 August 4, 2009한 달 제로 개월 차이를 산출? 당신은 무엇에 대해 다음 중 하나를 양보해야한다고 경우 July 31, 2009August 1, 2009? 가 한 달? 단순히 Month날짜 값 의 차이입니까 , 아니면 실제 시간 범위와 더 관련이 있습니까? 이러한 모든 규칙을 결정하는 논리는 사소한 것이 아니므로 자신의 규칙을 결정하고 적절한 알고리즘을 구현해야합니다.

날짜 값을 완전히 무시하고 단순히 달의 차이 만 원하는 경우 다음을 사용할 수 있습니다.

public static int MonthDifference(this DateTime lValue, DateTime rValue)
{
    return (lValue.Month - rValue.Month) + 12 * (lValue.Year - rValue.Year);
}

이는 상대적인 차이를 반환합니다. 즉, rValue이보다 크면 lValue반환 값이 음수입니다. 절대적인 차이를 원하면 다음을 사용할 수 있습니다.

public static int MonthDifference(this DateTime lValue, DateTime rValue)
{
    return Math.Abs((lValue.Month - rValue.Month) + 12 * (lValue.Year - rValue.Year));
}


답변

(이것은 오래된 질문이라는 것을 알고 있지만 …)

이다 상대적으로 순수 .NET에서 할 고통. 나는 특히 다음과 같은 것들을 위해 설계된 Noda Time 라이브러리를 추천 합니다.

LocalDate start = new LocalDate(2009, 10, 6);
LocalDate end = new LocalDate(2009, 12, 25);
Period period = Period.Between(start, end);
int months = period.Months;

(다른 옵션도 있습니다. 예를 들어 몇 년 동안 몇 달 동안 만 원하는 경우을 사용합니다 Period period = Period.Between(start, end, PeriodUnits.Months);)


답변

아마도 월의 분수에 대해 알고 싶지 않을 것입니다. 이 코드는 어떻습니까?


public static class DateTimeExtensions
{
    public static int TotalMonths(this DateTime start, DateTime end)
    {
        return (start.Year * 12 + start.Month) - (end.Year * 12 + end.Month);
    }
}

//  Console.WriteLine(
//     DateTime.Now.TotalMonths(
//         DateTime.Now.AddMonths(-1))); // prints "1"



답변

TotalMonths가 의미하는 바를 정의해야합니다.
간단한 정의는 한 달에 30.4 일 (365.25 / 12)입니다.

그 외에도 분수를 포함한 모든 정의는 쓸모없는 것처럼 보이며 더 일반적인 정수 값 (날짜 사이의 월 단위)도 비표준 비즈니스 규칙에 따라 다릅니다.


답변

나는에 아주 간단한 확장 메서드를 작성했습니다 DateTimeDateTimeOffset이 작업을 수행하는. 나는 그것이 TotalMonths속성 TimeSpan이 작동 하는 것과 똑같이 작동하기를 원했다 . 그것은 그것을 기반으로하기 때문에 DateTime.AddMonths()다른 달 길이를 존중하고 인간이 개월 기간으로 이해 한 것을 반환합니다.

(불행히도 TimeSpan에서 확장 방법으로 구현 할 수는 없습니다. 실제 사용 된 날짜에 대한 지식을 유지하지 못하기 때문에 수개월 동안 중요합니다.)

코드와 테스트는 모두 GitHub에서 사용할 수 있습니다 . 코드는 매우 간단합니다.

public static int GetTotalMonthsFrom(this DateTime dt1, DateTime dt2)
{
    DateTime earlyDate = (dt1 > dt2) ? dt2.Date : dt1.Date;
    DateTime lateDate = (dt1 > dt2) ? dt1.Date : dt2.Date;

    // Start with 1 month's difference and keep incrementing
    // until we overshoot the late date
    int monthsDiff = 1;
    while (earlyDate.AddMonths(monthsDiff) <= lateDate)
    {
        monthsDiff++;
    }

    return monthsDiff - 1;
}

그리고 모든 단위 테스트 사례를 통과합니다.

// Simple comparison
Assert.AreEqual(1, new DateTime(2014, 1, 1).GetTotalMonthsFrom(new DateTime(2014, 2, 1)));
// Just under 1 month's diff
Assert.AreEqual(0, new DateTime(2014, 1, 1).GetTotalMonthsFrom(new DateTime(2014, 1, 31)));
// Just over 1 month's diff
Assert.AreEqual(1, new DateTime(2014, 1, 1).GetTotalMonthsFrom(new DateTime(2014, 2, 2)));
// 31 Jan to 28 Feb
Assert.AreEqual(1, new DateTime(2014, 1, 31).GetTotalMonthsFrom(new DateTime(2014, 2, 28)));
// Leap year 29 Feb to 29 Mar
Assert.AreEqual(1, new DateTime(2012, 2, 29).GetTotalMonthsFrom(new DateTime(2012, 3, 29)));
// Whole year minus a day
Assert.AreEqual(11, new DateTime(2012, 1, 1).GetTotalMonthsFrom(new DateTime(2012, 12, 31)));
// Whole year
Assert.AreEqual(12, new DateTime(2012, 1, 1).GetTotalMonthsFrom(new DateTime(2013, 1, 1)));
// 29 Feb (leap) to 28 Feb (non-leap)
Assert.AreEqual(12, new DateTime(2012, 2, 29).GetTotalMonthsFrom(new DateTime(2013, 2, 28)));
// 100 years
Assert.AreEqual(1200, new DateTime(2000, 1, 1).GetTotalMonthsFrom(new DateTime(2100, 1, 1)));
// Same date
Assert.AreEqual(0, new DateTime(2014, 8, 5).GetTotalMonthsFrom(new DateTime(2014, 8, 5)));
// Past date
Assert.AreEqual(6, new DateTime(2012, 1, 1).GetTotalMonthsFrom(new DateTime(2011, 6, 10)));


답변

당신은 날짜 시간에 스스로 그것을 해결해야합니다. 스텁 일을 처리하는 방법은 사용하려는 대상에 따라 다릅니다.

한 가지 방법은 월을 계산 한 다음 마지막 날을 수정하는 것입니다. 다음과 같은 것 :

   DateTime start = new DateTime(2003, 12, 25);
   DateTime end = new DateTime(2009, 10, 6);
   int compMonth = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);
   double daysInEndMonth = (end - end.AddMonths(1)).Days;
   double months = compMonth + (start.Day - end.Day) / daysInEndMonth;


답변

나는 이렇게 할 것입니다 :

static int TotelMonthDifference(this DateTime dtThis, DateTime dtOther)
{
    int intReturn = 0;

    dtThis = dtThis.Date.AddDays(-(dtThis.Day-1));
    dtOther = dtOther.Date.AddDays(-(dtOther.Day-1));

    while (dtOther.Date > dtThis.Date)
    {
        intReturn++;
        dtThis = dtThis.AddMonths(1);
    }

    return intReturn;
}