两个日期之间的月份差异

Difference in months between two dates

提问人:Rauf 提问时间:1/9/2011 最后编辑:John SaundersRauf 更新时间:8/10/2022 访问量:451548

问:

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

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

TimeSpan ts = date1 - date2;

但这给了我以天为单位的数据。我不想将这个数字除以 30,因为不是每个月都是 30 天,而且由于两个操作数值彼此相距甚远,我担心除以 30 可能会给我一个错误的值。

有什么建议吗?

C# .NET vb.net 日期

评论

31赞 Cheng Chen 1/9/2011
定义“月差”,“2010年5月1日”和“2010年6月16日”之间有什么月差?1.5、1 还是别的什么?
8赞 stakx - no longer contributing 1/9/2011
或者,为了进一步强调这一点,2010 年 12 月 31 日和 2011 年 1 月 1 日之间的月份有什么区别?根据白天的不同,这可能只有 1 秒的差异;你会把这算作一个月的差异吗?
0赞 wirol 1/11/2012
这是简单而简短的代码,以防万一,您仍然无法得到答案,请参阅此帖子 stackoverflow.com/questions/8820603/...
15赞 Kirk Woll 2/10/2012
丹尼:1个月零15天。STAKX:0 个月零 1 天。关键是要获取月份组件。这对我来说似乎很明显,是一个很好的问题。
4赞 greg 3/31/2020
我认为既然 OP 提到了 vb 的 DateDiff,那么所有这些问题都得到了回答。答案恰好与 SQL Server 的 datediff 相同。只需回答问题...需要明确的是,这是两个日期之间跨越的月数(包括在内)

答:

582赞 Adam Ralph 1/9/2011 #1

假设月份中的某一天无关紧要(即 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

评论

3赞 Adam Ralph 1/9/2011
@Kurru - 365 / 12 只是一个月平均长度(以天为单位)的近似度量。这是一个不准确的衡量标准。对于较小的日期范围,这种不准确性是可以容忍的,但对于非常大的日期范围,这种不准确性可能会变得很严重。
35赞 DrunkCoder 11/22/2012
我认为有必要考虑日组件。像这样的东西(date1.Year - date2.Year) * 12 + date1.Month - date2.Month + (date1.Day >= date2.Day ? 0 : -1)
2赞 Adam Ralph 11/23/2012
@DrunkCoder这取决于给定系统的要求。在某些情况下,您的解决方案可能确实是最佳选择。例如,重要的是要考虑当两个日期跨越 31 天月、30 天月、2 月 28 日或 2 月 29 日时会发生什么。如果您的公式结果符合系统要求,那么这显然是正确的选择。如果没有,则需要其他东西。
6赞 Binary Worrier 9/30/2013
为了支持亚当所说的话,我花了数年时间为精算师编写代码。一些计算是除以天数,四舍五入 30 得到每月数字。有时计算月份,假设每个日期从每月的第一天开始计算月份,相应地计算整个月份。在计算日期方面,没有最好的方法。除非你是你正在为之编写代码的客户,否则请将其推回链上并澄清它,可能由你的客户会计师来澄清。
3赞 Gary 9/23/2015
365.2425 是公历中稍微准确的天数,如果您正在使用的话。但是,到 DateTime.MaxValue(10000 年 1 月 1 日)时,只有大约 59 天的差异。此外,根据您的观点 en.wikipedia.org/wiki/Year,年份的定义可能会有很大不同。
25赞 Cheng Chen 1/9/2011 #2

我通过MSDN检查了此方法在 VB.NET 中的用法,似乎它有很多用法。C# 中没有这样的内置方法。(即使这不是一个好主意)你可以在 C# 中调用 VB。

  1. 搭 您的项目作为参考Microsoft.VisualBasic.dll
  2. 在代码中使用Microsoft.VisualBasic.DateAndTime.DateDiff

评论

7赞 Adam Ralph 1/9/2011
为什么你认为这不是一个好主意?直观地说,我猜该库是运行时的“另一个 .NET 库”。请注意,我在这里扮演魔鬼的拥护者,我也不愿意这样做,因为它只是“感觉不对”(有点作弊),但我想知道是否有任何令人信服的技术理由不这样做。
3赞 Cody Gray - on strike 1/9/2011
@AdamRalph:完全没有理由不这样做。这些库是在 100% 托管代码中实现的,因此它与其他所有库都相同。唯一可以想象的区别是必须加载模块,但这样做所需的时间可以忽略不计。没有理由仅仅因为您选择用 C# 编写程序而欺骗自己,而放弃了经过全面测试的有用功能。(这也适用于类似的事情。Microsoft.VisualBasic.dllMy.Application.SplashScreen
4赞 Hans Passant 1/9/2011
如果你知道它是用 C# 编写的,你会改变主意吗?确实如此。按照同样的逻辑,使用System.Data和PresentationFramework也是作弊,其中很大一部分是用C++ / CLI编写的。
3赞 Cody Gray - on strike 1/9/2011
@AdamRalph:关于这个“奇怪的包袱”,有什么特别的例子浮现在脑海中吗?还是你纯粹是假设这么说的?是的,它可能会扰乱你的一些 C# 伙伴的思想,他们一直在编写大量代码来做一些你可以用正确的语句在一行中完成的事情,但我怀疑会不会有任何严重的损害。using
1赞 Adam Ralph 1/10/2011
@Cody Gray:同意,正如你所说明的那样,这个例子是微不足道的。这是通过调用这种不寻常的(来自 C# POV)方法引入的额外代码“噪音”,我很乐意避免。在一个组织良好的团队中,无论如何,这些事情都会在代码审查中被发现,并且可以很容易地避免。顺便说一句 - 我不是要攻击 VB6/VB.NET。我将这些方法描述为“奇怪”,只是因为从 .NET POV 来看,没有理由存在,因为它具有属性。它的存在只是为了使 VB.NET 看起来更像 VB6。作为一名前 VB6 程序员,我可以欣赏这一点;DateAndTime.Year()DateTimeYear
1赞 Mohammad Ali 8/14/2011 #3
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
51赞 Mongus Pong 9/21/2011 #4

你可以做

if ( date1.AddMonths(x) > date2 )

评论

0赞 lucky.expert 2/26/2018
这很简单,对我来说非常有效。我惊喜地发现,在计算从 1 个月末到下个月末天数较少的日期时,它按预期工作。例如。。2018 年 1 月 31 日 + 1 个月 = 2 月 28 日 218
0赞 barnacle.m 5/22/2018
这是更好的解决方案之一。
0赞 Cedric Arnould 2/27/2019
真正简单高效的解决方案!提出了最好的答案。
3赞 Tommix 3/9/2019
如果 date1 = 2018-10-28 和 date2 = 2018-12-21 怎么办?答案将是 2。而正确答案应该是 3。由于日期范围为 3 个月。如果我们只计算月份,忽略几天。所以这个答案是不正确的。
2赞 Chris Peacock 1/20/2021
我是不是错过了什么......这是对日期是否至少相差给定月数的真/错检查,而不是对该月数的计算,这是我认为 o/p 所要求的。
237赞 Kirk Woll 2/10/2012 #5

这是一个返回 a 的综合解决方案,类似于 ,只是除了时间部分之外,它还包括所有日期组件。DateTimeSpanTimeSpan

用法:

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

为方便起见,我已将逻辑归入结构中,但您可以将该方法移动到您认为合适的任何位置。另请注意,哪个日期在另一个日期之前并不重要。DateTimeSpanCompareDates

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

评论

2赞 Deeptechtons 11/26/2012
@KirkWoll谢谢。但是为什么 DateTimeSpan 返回这个日期时差的天数,实际上它是 timeanddate.com/date/......3435
0赞 Kirk Woll 11/26/2012
@Deeptechtons,不错的收获。您引起了我的注意,这些问题都与开始日期有关,并且日期“经过”了几天数较少的月份。我已经颠倒了逻辑(因此它从早到晚,反之亦然),现在在不修改当前日期的情况下累积月份(因此通过中间的月份,天数更少)仍然不完全确定与 相比时的理想结果应该是什么。现在结果是月。3110/31/201211/30/20121
2赞 jwg 8/21/2013
我写了一个答案 stackoverflow.com/a/17537472/1737957 一个类似的问题,测试了建议的答案(发现其中大多数都不起作用)。这个答案是为数不多的有效答案之一(根据我的测试套件)。链接到我的答案的github。
1赞 Enigmativity 6/3/2015
@KirkWoll - 此答案似乎不适用于开始日期的日期值高于结束日期的月份或源日期为闰日的边缘情况。尝试 - 它返回“1y 4m 1d”,但值应该是“1y 4m 0d”,对吧?2020-02-292021-06-29
1赞 Kirk Woll 4/3/2016
@Enigmativity,感谢您的评论。我通过在本节中处理这种情况来更新我的答案。似乎对我有用。Phase.Months
37赞 Guillaume86 3/26/2012 #6

如果你想要确切的整月数,总是正数(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 },
};

评论

0赞 Cristian Badila 12/17/2015
只是为了避免给其他人带来混淆,我认为这个解决方案是不正确的。使用测试用例:测试将失败,结果为 5。new { From = new DateTime(2015, 12, 31), To = new DateTime(2015, 6, 30), Result = 6 }
0赞 Cristian Badila 12/17/2015
在我在此处建议的修复程序中添加了一个快速要点
0赞 Guillaume86 12/18/2015
我不确定我明白了,我的函数应该返回 6:dotnetfiddle.net/MRZNnC
0赞 Cristian Badila 12/18/2015
我在这里手工复制了测试用例,它有一个错误。失败的规范应为:。“错误”在于代码中,它没有考虑到月份可以以不同的“月份中的某一天”结束。在这种情况下,从 2015 年 12 月 31 日到 2016 年 6 月 30 日,将过去整整 6 个月(因为 6 月有 30 天),但您的代码将返回 5。new { From = new DateTime(2015, 12, 31), To = new DateTime(2016, 06, 30), Result = 6 }to.Day < from.Day
3赞 Guillaume86 12/18/2015
在我看来,这是预期的行为,或者至少是我所期望的行为。我假设一个完整的月份是当你到达同一天(或像本例中那样的下个月)时。
1赞 Wayne 4/24/2012 #7

这是来自我自己的库,将返回两个日期之间的月差。

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

评论

1赞 Dave Cousineau 8/17/2014
这可行吗?我一直在纸上得到 11 分Jan-31-2014Dec-31-2013
-1赞 Tom 6/12/2012 #8

能够以月为单位计算 2 个日期之间的差异是一件完全合乎逻辑的事情,并且在许多业务应用程序中都是必需的。这里的几位编码员提供了诸如 - “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 个月(同样,额外的天数无关紧要)

在业务应用程序中,大多数时候,当你需要计算月份时,这是因为你需要根据人类计算时间的方式来了解“完整”的月份;不是基于一些抽象/无关紧要的想法。

评论

6赞 quetzalcoatl 4/25/2013
这就是为什么会计不是数学的原因之一。在会计中,结果取决于你的计算方式。我知道你的观点,我知道对此的“共同商业观点”,但这种解释显然是错误的。在 2012.11.30 和 2012.12.01 之间,有 0、1/30、1/31、1 或 2 个月,具体取决于您的要求。日期是排他性的还是包容性的?你有没有问过跨越、触摸或经过的月数?您想要四舍五入、四舍五入还是精确?
3赞 quetzalcoatl 4/25/2013
现在向商人或会计师解释,他们会给你一个困惑的表情。这总是“对他们来说太明显了,他们当然指的是 X、Y 和 Z,你怎么能有不同的想法?现在找几个商人,试着让他们就这个话题达成一致。会计师更有可能同意,因为在某些时候,他们会使用数学来检查他们可能会意外地将同一时期相加两次的选项,等等。甚至你的计算示例也是有争议的,并且依赖于区域,或者显然是无效的,因为它们假设了额外的业务规则,比如忽略额外的天数。
2赞 Jesse Webb 3/29/2014
-1 您假设所有软件都是“业务应用程序”。没有提到相关代码的用途。您还假设所有“业务应用程序”都具有相同的规则,这绝对不是真的。
1赞 Firnas 12/27/2012 #9

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

例如,从 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;
}
1赞 Sukanta 2/13/2013 #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);
}

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

2赞 Elmer 5/10/2013 #11

这适用于我需要它。就我而言,月份的某一天并不重要,因为它总是恰好是该月的最后一天。

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赞 R.Akhlaghi 9/30/2013 #12

我写了一个函数来实现这一点,因为其他方法对我不起作用。

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

评论

0赞 kleopatra 9/30/2013
请用英语回答(与任何发明的语言相比......
0赞 TabbyCool 4/15/2014
为什么不直接执行 startDate.AddMonths(monthCount)。ToShortDateString()?无论如何,这并不能回答最初提出的问题!
0赞 R.Akhlaghi 4/19/2014
哦,对不起@TabbyCool,这段代码在我的程序中运行良好!程序员规则说:首先代码有效,然后优化!tanx 供您评论:)
2赞 Patrice Calvé 10/17/2013 #13

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

评论

0赞 Ali Tabandeh 7/7/2023
如果月份的日期无关紧要,那么默认部分应该是这样的:12 * (end.Year - start.Year) - start.Month + end.Month;
0赞 Ivan 12/6/2013 #14

使用 ToString(format) 和 Duration(long ms) 扩展了 Kirks 结构

 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;
    }
}
1赞 GreatNate 1/8/2014 #15

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

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

例如,如果您的日期是 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
}
0赞 Paul 1/24/2014 #16
  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));
11赞 Chirag 4/5/2014 #17

要获得月份(包括开始和结束)的差异,无论日期如何:

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

评论

5赞 paul 12/18/2014
想象一下,并且是相同的。然后你得到的结果 1。这是怎么回事?为什么要在结果中加 1?谁在投票支持这个答案:-/ ?startend
0赞 Chirag 12/18/2014
对于相同的日期,它将给出 1 的输出。基本上,它将计算所有月份,包括开始和结束月份。
3赞 paul 12/18/2014
对我来说,这听起来不像是两个项目之间的区别。2 和 2 有什么区别?真的是1吗?我建议差异是 0。
0赞 flashsplat 8/11/2023
我无法理解它是如何工作的,但我把它放在 excel 中,它确实如此。我在末尾添加了 +1,因为就我而言,8/2023 - 8/2023 = 1 个月。他的解决方案确实说“开始和结束包容”。
4赞 user687474 4/5/2014 #18

可以将 .NET 的时间段库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
8赞 jenson-button-event 12/6/2014 #19

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

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

.NET 小提琴

0赞 Konstantin Chernov 1/21/2015 #20

以下是我们处理此问题的方法:

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;
    }
}
0赞 Bhavesh Patel 6/12/2015 #21
int nMonths = 0;
if (FDate.ToDateTime().Year == TDate.ToDateTime().Year)
     nMonths = TDate.ToDateTime().Month - FDate.ToDateTime().Month;                         
else
nMonths = (12 - FDate.Month) + TDate.Month;                          
11赞 Edward Brey 9/14/2015 #22

使用野田时间

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

(示例来源)

3赞 George Mavritsakis 10/2/2015 #23

我对 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

评论

0赞 bvj 8/26/2023
关于月百分比的不错方法
1赞 Waleed A.K. 10/23/2015 #24

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

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); 
2赞 Saeed Mahmoudi 11/7/2015 #25

最精确的方法是,以月为单位的分数返回差异:

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赞 Brent 4/29/2016 #26

这是一个更简洁的解决方案,仅对年、月、日使用 VB.Net DateDiff。您也可以在 C# 中加载 DateDiff 库。

date1 必须是 <= date2

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);
-2赞 Chethaka Wickramarathne 8/10/2016 #27

LINQ 解决方案,

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();
2赞 Simon Mourier 8/20/2016 #28

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

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);
}
4赞 Morgs 8/29/2016 #29

以下是我发现准确的月份差异的贡献:

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 的方法,并在 while 循环中应用与上述和 AddYears 完全相同的逻辑,而不是 AddMonths。

1赞 John A 4/21/2017 #30

这是对柯克·沃尔(Kirk Woll)回答的回应。我还没有足够的声望点数来回复评论......

我喜欢 Kirk 的解决方案,并打算无耻地将其撕掉并在我的代码中使用它,但当我浏览它时,我意识到它太复杂了。不必要的切换和循环,以及使用起来毫无意义的公共构造函数。

这是我的重写:

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,几乎相同:

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,类似:

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);
}
1赞 Ahmed 2/13/2018 #31

就我而言,需要计算从下个月开始日期到此日期前一天或从月初到月底的完整月份。


例:从 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);

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

-2赞 Mohammad S. Alam 6/1/2018 #32

简单修复。100%工作

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

评论

2赞 JeffC 6/1/2018
这是 5 年前此评论中 DrunkCoder 代码的精确副本。stackoverflow.com/questions/4638993/......
0赞 Patrick Oniel Bernardo 11/15/2018 #33
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;
    }
}
1赞 Dan Sutton 1/8/2019 #34

基于上面完成的出色 DateTimeSpan 工作,我对代码进行了一些规范化;这似乎效果很好:

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

评论

0赞 Bassie 2/19/2019
当与哪里和然后给我比较时CompareDates(x, y)x={01/02/2019 00:00:00}y={01/05/2020 00:00:00}Months2
0赞 Tommix 3/9/2019 #35

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

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赞 Eduardo Pelais 3/29/2019 #36

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

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.
            //

        }
0赞 Mircea Ion 4/26/2019 #37

似乎 DateTimeSpan 解决方案让很多人感到高兴。我不知道。让我们考虑一下:

开始日期 = 1972/2/29 结束日期 = 1972/4/28。

基于 DateTimeSpan 的答案是:

1年2个月0天

我实现了一个方法,基于此,答案是:

1年1个月28天

显然,那里没有整整 2 个月。我想说的是,因为我们处于开始日期的月底,所以剩下的实际上是 3 月的完整月份加上结束日期月份(4 月)经过的天数,所以 1 个月零 28 天。

如果您到目前为止阅读并且很感兴趣,我在下面发布了该方法。我在评论中解释了我所做的假设,因为有多少个月,几个月的概念是一个不断变化的目标。多次测试,看看答案是否有意义。我通常会选择相邻年份的考试日期,一旦我验证了答案,我就会来回移动一两天。到目前为止,它看起来不错,我相信你会:D发现一些错误。代码可能看起来有点粗糙,但我希望它足够清楚:

static void Main(string[] args) {
        DateTime EndDate = new DateTime(1973, 4, 28);
        DateTime BeginDate = new DateTime(1972, 2, 29);
        int years, months, days;
        GetYearsMonthsDays(EndDate, BeginDate, out years, out months, out days);
        Console.WriteLine($"{years} year(s), {months} month(s) and {days} day(s)");
    }

    /// <summary>
    /// Calculates how many years, months and days are between two dates.
    /// </summary>
    /// <remarks>
    /// The fundamental idea here is that most of the time all of us agree
    /// that a month has passed today since the same day of the previous month.
    /// A particular case is when both days are the last days of their respective months 
    /// when again we can say one month has passed.
    /// In the following cases the idea of a month is a moving target.
    /// - When only the beginning date is the last day of the month then we're left just with 
    /// a number of days from the next month equal to the day of the month that end date represent
    /// - When only the end date is the last day of its respective month we clearly have a 
    /// whole month plus a few days after the the day of the beginning date until the end of its
    /// respective months
    /// In all the other cases we'll check
    /// - beginingDay > endDay -> less then a month just daysToEndofBeginingMonth + dayofTheEndMonth
    /// - beginingDay < endDay -> full month + (endDay - beginingDay)
    /// - beginingDay == endDay -> one full month 0 days
    /// 
    /// </remarks>
    /// 
    private static void GetYearsMonthsDays(DateTime EndDate, DateTime BeginDate, out int years, out int months, out int days ) {
        var beginMonthDays = DateTime.DaysInMonth(BeginDate.Year, BeginDate.Month);
        var endMonthDays = DateTime.DaysInMonth(EndDate.Year, EndDate.Month);
        // get the full years
        years = EndDate.Year - BeginDate.Year - 1;
        // how many full months in the first year
        var firstYearMonths = 12 - BeginDate.Month;
        // how many full months in the last year
        var endYearMonths = EndDate.Month - 1;
        // full months
        months = firstYearMonths + endYearMonths;           
        days = 0;
        // Particular end of month cases
        if(beginMonthDays == BeginDate.Day && endMonthDays == EndDate.Day) {
            months++;
        }
        else if(beginMonthDays == BeginDate.Day) {
            days += EndDate.Day;
        }
        else if(endMonthDays == EndDate.Day) {
            days += beginMonthDays - BeginDate.Day;
        }
        // For all the other cases
        else if(EndDate.Day > BeginDate.Day) {
            months++;
            days += EndDate.Day - BeginDate.Day;
        }
        else if(EndDate.Day < BeginDate.Day) {                
            days += beginMonthDays - BeginDate.Day;
            days += EndDate.Day;
        }
        else {
            months++;
        }
        if(months >= 12) {
            years++;
            months = months - 12;
        }
    }
2赞 Michael 11/24/2019 #38

这个简单的静态函数计算两个日期时间之间的月数,例如

  • 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);
 }
4赞 Shah Zain 1/7/2020 #39

您可以使用Noda Time https://nodatime.org/

LocalDate start = new LocalDate(2010, 1, 5);
LocalDate end = new LocalDate(2012, 6, 1);
Period period = Period.Between(start, end, PeriodUnits.Months);
Console.WriteLine(period.Months);
0赞 Gambitier 5/8/2020 #40

除了所有给出的答案之外,我发现这段代码非常简单。AS DateTime.MinValue 是 1/1/1,我们必须从月、年和日中减去 1。

var timespan = endDate.Subtract(startDate);
var tempdate = DateTime.MinValue + timespan;

var totalMonths = (tempdate.Year - 1) * 12 + tempdate.Month - 1;

var totalDays = tempdate.Day - 1;
if (totalDays > 0)
{
    totalMonths = totalMonths + 1;
}
1赞 phil123456 2/19/2021 #41

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

助手类:

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;
    }
0赞 Miguel 10/18/2021 #42

如果您只关心月份和年份并想触摸这两个日期(例如,您想从 2021 年 1 月到 2022 年 AGO),您可以使用以下命令:

int numberOfMonths= (Year2 > Year1 ? ( Year2 - Year1 - 1) * 12 + (12 - Month1) + Month2 + 1 : Month2 - Month1 + 1); 

例:

Year1/Month1: 2021/10   
Year2/Month2: 2022/08   
numberOfMonths = 11;

或同年:

Year1/Month1: 2021/10   
Year2/Month2: 2021/12   
numberOfMonths = 3;

如果您只想触摸其中之一,请删除两个 + 1。

评论

0赞 Mal 8/29/2023
我使用这个的变体。获取 2 个日期的月份,如果日期少于要检查的日期,则删除一个月。int ageInMonths = (DateTime.Today.Year * 12) + DateTime.Today.Month - ((dob.年份 * 12) + 出生日期。Month) - (DateTime.Today.Day < dob.日?1 : 0);我期待找到像 TotalDays 这样的内置函数
2赞 Adam Janovec 11/10/2021 #43

单线解决方案

首先,检查两个日期是否都在当前年份,如果不是,则获取整年的月份,然后从开始和结束年份添加月份。

DateTime dateFrom = new DateTime(2019, 2, 1);
DateTime dateTo = new DateTime(2021, 5, 25);

随着第一个月

var monthCount = dateFrom.Year != dateTo.Year ? ((dateTo.Year - dateFrom.Year - 1) * 12) + (13 - dateFrom.Month + dateTo.Month) : dateTo.Month - dateFrom.Month + 1;

结果 = 28

没有第一个月

monthCount = dateFrom.Year != dateTo.Year ? ((dateTo.Year - dateFrom.Year - 1) * 12) + (12 - dateFrom.Month + dateTo.Month) : dateTo.Month - dateFrom.Month;

结果 = 27

2赞 Dan Hilderbrand 11/25/2021 #44

我正在做一个只用了几年和几个月的项目。

/// <summary>
/// Get the total months between two date.  This will count whole months and not care about the day.
/// </summary>
/// <param name="firstDate">First date.</param>
/// <param name="lastDate">Last date.</param>
/// <returns>Number of month apart.</returns>
private static int GetTotalMonths(DateOnly firstDate, DateOnly lastDate)
{
    int yearsApart = lastDate.Year - firstDate.Year;
    int monthsApart = lastDate.Month - firstDate.Month;
    return (yearsApart * 12) + monthsApart;
}

private static int GetTotalMonths(DateTime firstDate, DateTime lastDate)
{
    return GetTotalMonths(DateOnly.FromDateTime(firstDate), DateOnly.FromDateTime(lastDate));
}
1赞 EgoPingvina 8/10/2022 #45

一定是有人干的))

extension 方法返回给定日期之间的整月数。无论以何种顺序接收日期,都将始终返回一个自然数。没有像“正确”答案那样的近似计算。

    /// <summary>
    /// Returns the difference between dates in months.
    /// </summary>
    /// <param name="current">First considered date.</param>
    /// <param name="another">Second considered date.</param>
    /// <returns>The number of full months between the given dates.</returns>
    public static int DifferenceInMonths(this DateTime current, DateTime another)
    {
        DateTime previous, next;
        if (current > another)
        {
            previous = another;
            next     = current;
        }
        else
        {
            previous = current;
            next     = another;
        }

        return
            (next.Year - previous.Year) * 12     // multiply the difference in years by 12 months
          + next.Month - previous.Month          // add difference in months
          + (previous.Day <= next.Day ? 0 : -1); // if the day of the next date has not reached the day of the previous one, then the last month has not yet ended
    }

但是,如果您仍然想获得月份的小数部分,则只需在返回值中再添加一个项:

+ (next.Day - previous.Day) / DateTime.DaysInMonth(previous.Year, previous.Month)