关于c#:两个日期之间的月份差异

Difference in months between two dates

如何计算c_中两个日期之间的月份差异?

C中是否有与VB的DateDiff()方法等效的方法?我需要找出相隔几年的两个日期在几个月内的差异。文件上说我可以使用TimeSpan,比如:

1
TimeSpan ts = date1 - date2;

但这给了我几天的数据。我不想把这个数除以30,因为不是每个月都是30天,而且由于两个操作数的值彼此相差很远,所以恐怕除以30可能会给我一个错误的值。

有什么建议吗?


假设月日不相关(即2011.1.1和2010.12.31之间的差为1),其中date1>date2为正值,date2>date1为负值。

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

或者,假设您想要两个日期之间的"平均月数"的近似值,下面的内容应该适用于除非常巨大的日期差异之外的所有日期。

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

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

更新(感谢Gary)

如果使用"平均月数"方法,则"平均每年天数"使用的更准确数字为365.2425。


这里有一个全面的返回DateTimeSpan的解决方案,类似于TimeSpan的解决方案,除了包含时间组件外,还包含所有日期组件。

用途:

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}

输出:

Years: 1
Months: 5
Days: 27
Hours: 1
Minutes: 36
Seconds: 50
Milliseconds: 0

为了方便起见,我将逻辑集中到DateTimeSpan结构中,但是您可以将方法CompareDates移动到您认为合适的地方。另外要注意的是,哪个日期排在另一个日期之前并不重要。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
public struct DateTimeSpan
{
    public int Years { get; }
    public int Months { get; }
    public int Days { get; }
    public int Hours { get; }
    public int Minutes { get; }
    public int Seconds { get; }
    public int Milliseconds { get; }

    public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
    {
        Years = years;
        Months = months;
        Days = days;
        Hours = hours;
        Minutes = minutes;
        Seconds = seconds;
        Milliseconds = 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),考虑到完整月份是您下个月的同一天(类似于年龄计算)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
    }
}

编辑原因:旧代码在某些情况下不正确,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 },
};


你可以做到

1
if ( date1.AddMonths(x) > date2 )


我通过msdn检查了这个方法在vb.net中的用法,它似乎有很多用法。在C中没有这样的内置方法。(即使这不是一个好主意)你也可以用C语言调用vb。

  • Microsoft.VisualBasic.dll添加到你的项目作为参考
  • 使用Microsoft.VisualBasic.DateAndTime.DateDiff在您的代码中

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

    1
    2
    3
    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);


    我只需要一些简单的事情来满足,例如,只输入月份/年份的就业日期,所以需要不同的年份和月份。这是我用的,这里只是为了有用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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
        };
    }

    网提琴


    使用野田时间:

    1
    2
    3
    4
    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

    (示例来源)


    可以使用.NET时间段库的datediff类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // ----------------------------------------------------------------------
    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


    这是一个简单的解决方案,至少对我有效。但它可能不是最快的,因为它在循环中使用了酷的datetime的addmonth功能:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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);
    }

    这是我所需要的。在我的情况下,一个月的最后一天并不重要,因为它总是恰好是一个月的最后一天。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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;
    }

    最精确的方法是按分数返回月份差异:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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;
    }

    以下是我对在几个月内获得准确差异的贡献:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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;
            }
        }
    }

    用途:

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

    您可以创建另一个名为diffyears的方法,并在while循环中应用与上面和addyears完全相同的逻辑,而不是addmonths。


    基于上面所做的出色的DateTimeSpan工作,我对代码进行了一点规范化;这似乎非常有效:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    public class DateTimeSpan
    {
      private DateTimeSpan() { }

      private DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
      {
        Years = years;
        Months = months;
        Days = days;
        Hours = hours;
        Minutes = minutes;
        Seconds = seconds;
        Milliseconds = milliseconds;
      }

      public int Years { get; private set; } = 0;
      public int Months { get; private set; } = 0;
      public int Days { get; private set; } = 0;
      public int Hours { get; private set; } = 0;
      public int Minutes { get; private set; } = 0;
      public int Seconds { get; private set; } = 0;
      public int Milliseconds { get; private set; } = 0;

      public static DateTimeSpan CompareDates(DateTime StartDate, DateTime EndDate)
      {
        if (StartDate.Equals(EndDate)) return new DateTimeSpan();
        DateTimeSpan R = new DateTimeSpan();
        bool Later;
        if (Later = StartDate > EndDate)
        {
          DateTime D = StartDate;
          StartDate = EndDate;
          EndDate = D;
        }

        // Calculate Date Stuff
        for (DateTime D = StartDate.AddYears(1); D < EndDate; D = D.AddYears(1), R.Years++) ;
        if (R.Years > 0) StartDate = StartDate.AddYears(R.Years);
        for (DateTime D = StartDate.AddMonths(1); D < EndDate; D = D.AddMonths(1), R.Months++) ;
        if (R.Months > 0) StartDate = StartDate.AddMonths(R.Months);
        for (DateTime D = StartDate.AddDays(1); D < EndDate; D = D.AddDays(1), R.Days++) ;
        if (R.Days > 0) StartDate = StartDate.AddDays(R.Days);

        // Calculate Time Stuff
        TimeSpan T1 = EndDate - StartDate;
        R.Hours = T1.Hours;
        R.Minutes = T1.Minutes;
        R.Seconds = T1.Seconds;
        R.Milliseconds = T1.Milliseconds;

        // Return answer. Negate values if the Start Date was later than the End Date
        if (Later)
          return new DateTimeSpan(-R.Years, -R.Months, -R.Days, -R.Hours, -R.Minutes, -R.Seconds, -R.Milliseconds);
        return R;
      }
    }


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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);
    }

    此解决方案用于租金/订阅计算,其中差异并不意味着要减去,而是指这两个日期内的跨度。


    我写了一个函数来完成这个任务,因为其他方法对我来说不起作用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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());
    }


    有三种情况:同一年、上一年和其他年份。

    如果一个月的某一天无关紧要…

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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;
        }
    }

    这是从我自己的图书馆,会返回两个日期之间的月差。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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;
    }


    在我的情况下,需要计算从开始日期到下个月的前一天或从开始到月末的整个月。

    例如:从2018年1月1日到2018年1月31日是一个完整的月ex2:从2018年5月1日到2018年4月2日是一个完整的月

    基于此,我的解决方案是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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;
    }

    用途:

    1
    Tuple<int, int> Period = CalcPeriod(FromDate, ToDate);

    注意:在我的例子中,需要计算完成月份后的剩余天数,因此如果不是您的情况,您可以忽略天数结果,甚至可以将方法返回从元组更改为整数。


    你可以有这样一个函数。

    例如,从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个月。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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;
    }

    这是为了回应柯克·沃尔的回答。我还没有足够的信誉点来回复评论…

    我喜欢柯克的解决方案,并且会无耻地将它撕掉并在我的代码中使用它,但是当我查看它时,我发现它太复杂了。不必要的切换和循环,以及一个无意义的公共构造函数。

    这是我的重写:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    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);
        }
    }

    用法1大致相同:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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);
    }

    用途2,类似:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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);
    }

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

    此解决方案计算两个日期之间的月数,假设要保存月的某一天进行比较(即计算中考虑月的某一天)。

    例如,如果您的日期是2012年1月30日,那么2012年2月29日不是一个月,而是2013年3月1日。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    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
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    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

    我对两个日期之间的总月份差异的理解有一个整数部分和一个小数部分(日期很重要)。

    不可分割的部分是整个月份的差异。

    对于我来说,小数部分是开始月份和结束月份之间当天(到整个月份)的百分比的差额。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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;
        }
    }

    有了这个扩展,结果如下:

    1
    2
    3
    4
    5
    6
    7
    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


    您可以使用以下扩展名:代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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
    }

    实施!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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。您也可以在C中加载datediff库。

    日期1必须小于等于日期2

    VB.NET

    1
    2
    3
    4
    5
    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.*

    1
    2
    3
    4
    5
    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);

    简单快速的解决方案,可计算两个日期之间的总月数。如果您只想得到不同的月份,而不计算"开始日期"中的月份,只需从代码中删除+1即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public static int GetTotalMonths(DateTime From, DateTime Till)
            {
                int MonthDiff = 0;

                for (int i = 0; i < 12; i++)
                {
                    if (From.AddMonths(i).Month == Till.Month)
                    {
                        MonthDiff = i + 1;
                        break;
                    }
                }

                return MonthDiff;
            }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {

            label3.Text = new DateDifference(Convert.ToDateTime("2018-09-13"), Convert.ToDateTime("2018-11-15")).ToString();
            label2.Text = new DateDifference(Convert.ToDateTime("2018-10-12"), Convert.ToDateTime("2018-11-15")).ToString();

            DateDifference oDateDifference = new DateDifference(Convert.ToDateTime("2018-11-12"));
           label1.Text  =   oDateDifference.ToString();

        }
    }




    public class DateDifference
    {
        public DateTime start { get; set; }
        public DateTime currentDAte { get; set; }
        public DateTime origstart { get; set; }
        public DateTime origCurrentDAte { get; set; }

        int days { get; set; }
        int months { get; set; }
        int years { get; set; }

        public DateDifference(DateTime postedDate, DateTime currentDAte)
        {
            this.start = this.removeTime(postedDate);
            this.currentDAte = this.removeTime(currentDAte);
            this.origstart = postedDate;
            this.origCurrentDAte = currentDAte;

        }

        public DateDifference(DateTime postedDate)
        {
            DateTime currentDate_ = DateTime.Now;
            this.start = this.removeTime(postedDate);
            this.currentDAte = this.removeTime(currentDate_);
            this.origstart = postedDate;
            this.origCurrentDAte = currentDate_;
            if (start > this.currentDAte)
            {
                throw new Exception("Current date is greater than date posted");
            }
            this.compute();
        }

        void compute()
        {
            while (this.start.Year <= this.currentDAte.Year)
            {
                if (this.start.Year <= this.currentDAte.Year && (this.start.AddMonths(1) <= this.currentDAte))
                {
                    ++this.months;
                    this.start = this.start.AddMonths(1);
                }

                if ((this.start.Year == this.currentDAte.Year) && (this.start >= this.currentDAte.AddMonths(-1) && this.start <= this.currentDAte))
                {
                    break;
                }
            }

            while (this.start.DayOfYear < this.currentDAte.DayOfYear)
            {
                ++this.days;
                this.start = start.AddDays(1);
            }

            if (this.months > 11)
            {
                while (this.months > 11)
                {
                    ++this.years;
                    this.months = months - 12;
                }
            }

        }


        public override string ToString()
        {
            if (this.start > this.currentDAte)
            {
                throw new Exception("Current date is greater than date posted");
            }
            String ret = this.ComposeTostring();
            this.reset();
            return ret;
        }

        private String ComposeTostring()
        {
            this.compute();
            if (this.years > 0)
            {
                if (this.months > 0)
                {
                    if (this.days > 0)
                    {
                        return String.Format("{0} year{1}, {2} month{3} && {4} Day{5} ago", this.years, plural(this.years), this.months, plural(this.months), this.days, plural(this.days));
                    }
                    return String.Format("{0} year{1}, {2} month{3} ago", this.years, plural(this.years), this.months, plural(this.months));
                }
                else
                {
                    if (this.days > 0)
                    {
                        return String.Format("{0} year{1},{2} day{3} ago", this.years, plural(this.years), this.days, plural(this.days));
                    }

                    return String.Format("{0} year{1} ago", this.years, plural(this.years));

                }
            }

            if (this.months > 0)
            {
                if (this.days > 0)
                {
                    return String.Format("{0} month{1}, {2} day{3} ago", this.months, plural(this.months), this.days, plural(this.days));
                }
                else
                {
                    return String.Format("{0} month{1} ago", this.months, plural(this.months));
                }
            }

            if ((this.origCurrentDAte - this.origstart).Days > 0)
            {
                int daysDiff = (this.origCurrentDAte - this.origstart).Days;
                this.origstart = this.origstart.AddDays(daysDiff);
                int HoursDiff = (this.origCurrentDAte - this.origstart).Hours;
                return String.Format("{0} day{1}, {2} hour{3} ago", daysDiff, plural(daysDiff), HoursDiff, plural(HoursDiff));

            }
            else if ((this.origCurrentDAte - this.origstart).Hours > 0)
            {
                int HoursDiff = (this.origCurrentDAte - this.origstart).Hours;
                this.origstart = this.origstart.AddHours(HoursDiff);
                int MinDiff = (this.origCurrentDAte - this.origstart).Minutes;
                return String.Format("{0} hour{1}, {2} minute{3} ago", HoursDiff, plural(HoursDiff), MinDiff, plural(MinDiff));
            }
            else if ((this.origCurrentDAte - this.origstart).Minutes > 0)
            {

                int MinDiff = (this.origCurrentDAte - this.origstart).Minutes;
                this.origstart = this.origstart.AddMinutes(MinDiff);
                int SecDiff = (this.origCurrentDAte - this.origstart).Seconds;
                return String.Format("{0} minute{1}, {2} second{3} ago", MinDiff, plural(MinDiff), SecDiff, plural(SecDiff));
            }
            else if ((this.origCurrentDAte - this.origstart).Seconds > 0)
            {
                int sec = (this.origCurrentDAte - this.origstart).Seconds;
                return String.Format("{0} second{1}", sec, plural(sec));
            }

            return"";
        }

        String plural(int val)
        {
            return (val > 1 ?"s" : String.Empty);
        }

        DateTime removeTime(DateTime dtime)
        {
            dtime = dtime.AddHours(-dtime.Hour);
            dtime = dtime.AddMinutes(-dtime.Minute);
            dtime = dtime.AddSeconds(-dtime.Second);
            return dtime;
        }

        public void reset()
        {

            this.days = 0;
            this.months = 0;
            this.years = 0;
            this.start = DateTime.MinValue;
            this.currentDAte = DateTime.MinValue;
            this.origstart = DateTime.MinValue;
            this.origCurrentDAte = DateTime.MinValue;
        }
    }

    要能够在几个月内计算两个日期之间的差异,这是一件非常合乎逻辑的事情,而且在许多业务应用程序中都需要这样做。这里的几位编码员提供了一些评论,比如"2010年5月1日"和"2010年6月16日"之间的月份有什么区别,2010年12月31日和2011年1月1日之间的月份有什么区别?--无法理解业务应用程序的基本知识。

    以上2条意见的答案是:2010年5月1日至2010年6月16日为1个月,2010年12月31日至2011年1月1日为0个月。按照上面的编码人员的建议,将它们计算为1.5个月1秒是非常愚蠢的。

    从事过信用卡、抵押贷款处理、税务处理、租金处理、每月利息计算和各种其他业务解决方案的人都会同意。

    问题是这样一个函数不包括在C或vb.net中。datediff只考虑年份或月份组件,因此实际上是无用的。

    以下是一些您需要并正确计算月份的实际示例:

    你在2月18日至8月23日的短期租房里住过。你在那里住了多少个月?答案很简单-6个月

    你有一个银行账户,每个月底计算并支付利息。6月10日存款,10月29日(同年)取出。你有多少个月的利息?非常简单的答案-4个月(同样,额外的天数也不重要)

    在业务应用程序中,大多数情况下,当您需要计算月份时,这是因为您需要知道"完整"月份是基于人类如何计算时间的,而不是基于一些抽象/无关的想法。


    1
    2
    3
    4
    5
      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));

    我的问题用这个解决方案解决了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    static void Main(string[] args)
            {
                var date1 = new DateTime(2018, 12, 05);
                var date2 = new DateTime(2019, 03, 01);

                int CountNumberOfMonths() => (date2.Month - date1.Month) + 12 * (date2.Year - date1.Year);

                var numberOfMonths = CountNumberOfMonths();

                Console.WriteLine("Number of months between {0} and {1}: {2} months.", date1.ToString(), date2.ToString(), numberOfMonths.ToString());

                Console.ReadKey();

                //
                // *** Console Output:
                // Number of months between 05/12/2018 00:00:00 and 01/03/2019 00:00:00: 3 months.
                //

            }

    以下是我们的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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;
        }
    }

    1
    2
    3
    4
    5
    int nMonths = 0;
    if (FDate.ToDateTime().Year == TDate.ToDateTime().Year)
         nMonths = TDate.ToDateTime().Month - FDate.ToDateTime().Month;                        
    else
    nMonths = (12 - FDate.Month) + TDate.Month;

    扩展的Kirks结构,带有ToString(格式)和Duration(长ms)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
     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;
        }
    }

    简单的修复。作品100%

    1
    2
    3
            var exactmonth = (date1.Year - date2.Year) * 12 + date1.Month -
            date2.Month +  (date1.Day >= date2.Day ? 0 : -1);
            Console.WriteLine(exactmonth);


    LINQ方案

    1
    2
    3
    4
    5
    6
    7
    8
    DateTime ToDate = DateTime.Today;
    DateTime FromDate = ToDate.Date.AddYears(-1).AddDays(1);

    int monthCount = Enumerable.Range(0, 1 + ToDate.Subtract(FromDate).Days)
                        .Select(x => FromDate.AddDays(x))
                        .ToList<DateTime>()
                        .GroupBy(z => new { z.Year, z.Month })
                        .Count();