如何在c#中计算两个日期之间的月差?

c#中是否有相当于VB的DateDiff()方法。我需要找出相隔数年的两个日期之间的月差。文档说我可以像这样使用TimeSpan:

TimeSpan ts = date1 - date2;

但这里的数据是以天为单位的。我不想把这个数字除以30,因为不是每个月都是30天,而且两个操作数的值相差很大,所以我担心除以30可能会得到错误的值。

有什么建议吗?


当前回答

扩展的Kirks结构与ToString(格式)和持续时间(长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;
    }
}

其他回答

这是我所需要的。对我来说,一个月的哪一天并不重要,因为它总是碰巧是一个月的最后一天。

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;
}

有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;
    }
}

下面是一个使用VB的更简洁的解决方案。只适用于年、月、日的净日期。你也可以在c#中加载DateDiff库。

Date1必须<= date2

VB。网

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);

你可以这样做

if ( date1.AddMonths(x) > date2 )

在这个问题上没有很多明确的答案,因为你总是在假设事情。

这个解决方案在两个日期之间进行计算,假设您想保存一个月中的某一天进行比较,(这意味着在计算中考虑了这个月中的某一天)

例如,如果你的日期是2012年1月30日,2012年2月29日就不是一个月,但2013年3月1日就不是一个月。

它经过了相当彻底的测试,可能稍后我们会在使用时清理它,但这里:

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
}