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

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

TimeSpan ts = date1 - date2;

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

有什么建议吗?


当前回答

疯狂的方法,计算所有的日子,超级精确

Helper类:

public class DaysInMonth
{
    public int Days { get; set; }
    public int Month { get; set; }
    public int Year { get; set; }
    public bool Full { get; set; }
}

功能:

    public static List<DaysInMonth> MonthsDelta(DateTime start, DateTime end)
    {
        
        var dates = Enumerable.Range(0, 1 + end.Subtract(start).Days)
          .Select(offset => start.AddDays(offset))
          .ToArray();

        DateTime? prev = null;
        int days = 0;

        List < DaysInMonth > list = new List<DaysInMonth>();

        foreach (DateTime date in dates)
        {
            if (prev != null)
            {
                if(date.Month!=prev.GetValueOrDefault().Month)
                {
                    DaysInMonth daysInMonth = new DaysInMonth();
                    daysInMonth.Days = days;
                    daysInMonth.Month = prev.GetValueOrDefault().Month;
                    daysInMonth.Year = prev.GetValueOrDefault().Year;
                    daysInMonth.Full = DateTime.DaysInMonth(daysInMonth.Year, daysInMonth.Month) == daysInMonth.Days;
                    list.Add(daysInMonth);
                    days = 0;
                }
            }
            days++;
            prev = date;
        }

        //------------------ add last
        if (days > 0)
        {
            DaysInMonth daysInMonth = new DaysInMonth();
            daysInMonth.Days = days;
            daysInMonth.Month = prev.GetValueOrDefault().Month;
            daysInMonth.Year = prev.GetValueOrDefault().Year;
            daysInMonth.Full = DateTime.DaysInMonth(daysInMonth.Year, daysInMonth.Month) == daysInMonth.Days;
            list.Add(daysInMonth);
        }

        return list;
    }

其他回答

这个简单的静态函数计算两个Datetimes之间的月份分数。

1.1. 到31.1。= 1.0 1.4. 到15.4。= 0.5 16.4. 到30.4。= 0.5 1.3. 到1.4。= 1 + 1/30

该函数假设第一个日期比第二个日期小。要处理负时间间隔,可以通过在开始时引入符号和变量交换来轻松地修改函数。

public static double GetDeltaMonths(DateTime t0, DateTime t1)
{
     DateTime t = t0;
     double months = 0;
     while(t<=t1)
     {
         int daysInMonth = DateTime.DaysInMonth(t.Year, t.Month);
         DateTime endOfMonth = new DateTime(t.Year, t.Month, daysInMonth);
         int cutDay = endOfMonth <= t1 ? daysInMonth : t1.Day;
         months += (cutDay - t.Day + 1) / (double) daysInMonth;
         t = new DateTime(t.Year, t.Month, 1).AddMonths(1);
     }
     return Math.Round(months,2);
 }

要获得月份的差异(包括开始和结束),而不考虑日期:

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

你可以有一个这样的函数。

例如,从2012/12/27到2012/12/29变成3天。同样,从2012/12/15到2013/01/15变成了2个月,因为到2013/01/14是1个月。从15号开始是第二个月。

如果您不想在计算中包括这两天,则可以删除第二个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;
}
int nMonths = 0;
if (FDate.ToDateTime().Year == TDate.ToDateTime().Year)
     nMonths = TDate.ToDateTime().Month - FDate.ToDateTime().Month;                         
else
nMonths = (12 - FDate.Month) + TDate.Month;                          

假设这个月的日期不相关(即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)

注意,如果您要使用后一种解决方案,那么您的单元测试应该声明应用程序设计使用的最宽日期范围,并相应地验证计算结果。


更新(感谢Gary)

如果使用“平均月份”方法,“每年平均天数”的更准确数字是365.2425。