计算两个date之间的月差

在C#/。NET TimeSpanTotalDaysTotalMinutes等,但我不知道总月份差异的公式。 每个月可变的日子和闰年不断地把我抛弃。 我怎样才能得到TotalMonths

编辑对不起,不是更清楚:我知道我实际上不能从TimeSpan得到这个,但我认为使用TotalDaysTotalMinutes将是一个很好的例子来expression我在找的东西…除了我试图得到Total Months 。

例如:2009年12月25日 – 2009年10月6日= 2个月总数。 10月6日至11月5日等于0个月。 11月6日,1个月。 12月6日,2个月

你将无法从TimeSpan获得,因为“月”是一个可变的计量单位。 你将不得不自己计算一下,你必须弄清楚你想如何工作。

例如,如果像July 5, 2009July 5, 2009 August 4, 2009产生一个月或零个月的差异? 如果你说它应该产生一个,那么July 31, 2009July 31, 2009 August 1, 2009呢? 是一个月吗? 它仅仅是date的Month值的差异,还是与实际的时间跨度更相关? 确定所有这些规则的逻辑是非平凡的,所以你必须确定你自己的和实现适当的algorithm。

如果你想要的仅仅是几个月的差异 – 完全忽略date值 – 那么你可以使用这个:

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

请注意,这将返回相对差异,这意味着如果rValue大于lValue ,则返回值将为负值。 如果你想要一个绝对的差异,你可以使用这个:

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

(我知道这是一个老问题,但…)

在纯.NET中这是相当痛苦的。 我推荐我自己的Noda时间库,这是专门为这样的事情devise的:

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

(还有其他的select,例如,如果你只想要几个月甚至几年,你会使用Period period = Period.Between(start, end, PeriodUnits.Months);

也许你不想知道月份分数; 这个代码呢?

public static class DateTimeExtensions { public static int TotalMonths(this DateTime start, DateTime end) { return (start.Year * 12 + start.Month) - (end.Year * 12 + end.Month); } } // Console.WriteLine( // DateTime.Now.TotalMonths( // DateTime.Now.AddMonths(-1))); // prints "1"
public static class DateTimeExtensions { public static int TotalMonths(this DateTime start, DateTime end) { return (start.Year * 12 + start.Month) - (end.Year * 12 + end.Month); } } // Console.WriteLine( // DateTime.Now.TotalMonths( // DateTime.Now.AddMonths(-1))); // prints "1" 

您将不得不定义TotalMonths开始的含义。
简单的定义是30.4天(365.25 / 12)。

除此之外,包括分数在内的任何定义似乎都是无用的,更常见的整数值(date之间的整个月份)也取决于非标准的业务规则。

你需要在date之外自行解决。 如何处理最后的存根date将取决于你想要使用它。

一种方法是计算月份,然后修正最后几天。 就像是:

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

我已经写了一个非常简单的DateTimeDateTimeOffset扩展方法来做到这一点。 我希望它能像TimeSpan上的TotalMonths属性一样工作:即返回两个date之间的完整月数,忽略任何部分月份。 因为它基于DateTime.AddMonths()所以它遵循不同的月份长度,并返回一个人在几个月内会理解的内容。

(不幸的是,你不能在TimeSpan上实现它作为扩展方法,因为它不能保留实际使用date的知识,而且几个月它们很重要。)

代码和testing都可以在GitHub上find 。 代码非常简单:

 public static int GetTotalMonthsFrom(this DateTime dt1, DateTime dt2) { DateTime earlyDate = (dt1 > dt2) ? dt2.Date : dt1.Date; DateTime lateDate = (dt1 > dt2) ? dt1.Date : dt2.Date; // Start with 1 month's difference and keep incrementing // until we overshoot the late date int monthsDiff = 1; while (earlyDate.AddMonths(monthsDiff) <= lateDate) { monthsDiff++; } return monthsDiff - 1; } 

它通过了所有这些unit testing用例:

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

我会这样做:

 static int TotelMonthDifference(this DateTime dtThis, DateTime dtOther) { int intReturn = 0; dtThis = dtThis.Date.AddDays(-(dtThis.Day-1)); dtOther = dtOther.Date.AddDays(-(dtOther.Day-1)); while (dtOther.Date > dtThis.Date) { intReturn++; dtThis = dtThis.AddMonths(1); } return intReturn; } 

几个月的问题是,这不是一个简单的措施 – 他们不是一个固定的大小。 你需要定义你想要包含的规则,并从那里开始工作。 例如1月1日至2月1日 – 你可能会争论2个月,或者你可以说是一个月。 那么“1月1日20:00”到“2月1日00:00”这个不是整整一整个月。 那是0吗? 1? 那么相反呢(1月1日00:00至2月1日20:00)… 1? 2?

首先定义规则,然后你必须自己编码,恐怕…

如果你想在28th Feb 1st March 28th Feb1st March 28th Feb 1st March之间得到结果1

 DateTime date1, date2; int monthSpan = (date2.Year - date1.Year) * 12 + date2.Month - date1.Month 

考虑到DateTime的所有部分, 该库计算月份的差异:

 // ---------------------------------------------------------------------- public void DateDiffSample() { DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 ); Console.WriteLine( "Date1: {0}", date1 ); // > Date1: 08.11.2009 07:13:59 DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 ); Console.WriteLine( "Date2: {0}", date2 ); // > Date2: 20.03.2011 19:55:28 DateDiff dateDiff = new DateDiff( date1, date2 ); // differences Console.WriteLine( "DateDiff.Years: {0}", dateDiff.Years ); // > DateDiff.Years: 1 Console.WriteLine( "DateDiff.Quarters: {0}", dateDiff.Quarters ); // > DateDiff.Quarters: 5 Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months ); // > DateDiff.Months: 16 Console.WriteLine( "DateDiff.Weeks: {0}", dateDiff.Weeks ); // > DateDiff.Weeks: 70 Console.WriteLine( "DateDiff.Days: {0}", dateDiff.Days ); // > DateDiff.Days: 497 Console.WriteLine( "DateDiff.Weekdays: {0}", dateDiff.Weekdays ); // > DateDiff.Weekdays: 71 Console.WriteLine( "DateDiff.Hours: {0}", dateDiff.Hours ); // > DateDiff.Hours: 11940 Console.WriteLine( "DateDiff.Minutes: {0}", dateDiff.Minutes ); // > DateDiff.Minutes: 716441 Console.WriteLine( "DateDiff.Seconds: {0}", dateDiff.Seconds ); // > DateDiff.Seconds: 42986489 // elapsed Console.WriteLine( "DateDiff.ElapsedYears: {0}", dateDiff.ElapsedYears ); // > DateDiff.ElapsedYears: 1 Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths ); // > DateDiff.ElapsedMonths: 4 Console.WriteLine( "DateDiff.ElapsedDays: {0}", dateDiff.ElapsedDays ); // > DateDiff.ElapsedDays: 12 Console.WriteLine( "DateDiff.ElapsedHours: {0}", dateDiff.ElapsedHours ); // > DateDiff.ElapsedHours: 12 Console.WriteLine( "DateDiff.ElapsedMinutes: {0}", dateDiff.ElapsedMinutes ); // > DateDiff.ElapsedMinutes: 41 Console.WriteLine( "DateDiff.ElapsedSeconds: {0}", dateDiff.ElapsedSeconds ); // > DateDiff.ElapsedSeconds: 29 } // DateDiffSample 

老问题我知道,但可能会帮助别人。 我已经使用@Adam接受上面的答案,但然后检查是否差异是1或-1,然后检查,看看是否是一个完整的日历月的差异。 所以21/07/55和20/08/55不会是整整一个月份,但21/07/55和21/07/55会是。

 /// <summary> /// Amended date of birth cannot be greater than or equal to one month either side of original date of birth. /// </summary> /// <param name="dateOfBirth">Date of birth user could have amended.</param> /// <param name="originalDateOfBirth">Original date of birth to compare against.</param> /// <returns></returns> public JsonResult ValidateDateOfBirth(string dateOfBirth, string originalDateOfBirth) { DateTime dob, originalDob; bool isValid = false; if (DateTime.TryParse(dateOfBirth, out dob) && DateTime.TryParse(originalDateOfBirth, out originalDob)) { int diff = ((dob.Month - originalDob.Month) + 12 * (dob.Year - originalDob.Year)); switch (diff) { case 0: // We're on the same month, so ok. isValid = true; break; case -1: // The month is the previous month, so check if the date makes it a calendar month out. isValid = (dob.Day > originalDob.Day); break; case 1: // The month is the next month, so check if the date makes it a calendar month out. isValid = (dob.Day < originalDob.Day); break; default: // Either zero or greater than 1 month difference, so not ok. isValid = false; break; } if (!isValid) return Json("Date of Birth cannot be greater than one month either side of the date we hold.", JsonRequestBehavior.AllowGet); } else { return Json("Date of Birth is invalid.", JsonRequestBehavior.AllowGet); } return Json(true, JsonRequestBehavior.AllowGet); } 

下面实际上是你能做到的最准确的方法,因为“1个月”的定义取决于它是哪个月份,而其他答案中没有考虑到这个问题! 如果你想了解更多关于这个问题的信息,那么你可以阅读这篇文章: 一个带有.Years&.Months的Real TimeSpan对象 (然而,阅读这篇文章并不需要理解和使用下面的函数,它的工作原理是100%,没有其他人喜欢使用的逼近的内在不准确性,并且可以随意使用框架中的内置.Reverse函数replace.ReverseIt函数(这里只是为了完整性)。

请注意,您可以获得任意数量的date/时间准确性,秒和分钟,或者秒,分钟和天,任何地方长达几年(将包含6个部分/段)。 如果您指定的是前两名,并且已经超过一年,则将返回“1年3个月前”,因为您请求了两个细分受众群而不会返回其他项目。 如果只有几个小时的时间,那么它只会返回“2小时1分钟前”。 当然,如果您指定1,2,3,4,5或6个分段(最多6分钟,因为秒,分钟,小时,天,月,年只有6种types),同样的规则也适用。 它也将修正语法问题,如“分钟”与“分钟”,取决于是否1分钟或更长时间,对于所有types相同,并且生成的“string”总是在语法上是正确的。

这里有一些使用的例子:bAllowSegments标识了要显示多less段…即:如果是3,则返回string将是(作为示例)… "3 years, 2 months and 13 days" (将不包括小时,分钟和秒作为前3个时间类别返回),但是,如果date是一个较新的date,如几天前,指定相同的段(3)将返回"4 days, 1 hour and 13 minutes ago" ,所以它考虑到了一切!

如果bAllowSegments为2,则返回"3 years and 2 months" ,如果6(最大值)返回"3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds" ,但是要提醒它NEVER RETURN像这样"0 years, 0 months, 0 days, 3 hours, 2 minutes and 13 seconds ago"这样的东西NEVER RETURN "0 years, 0 months, 0 days, 3 hours, 2 minutes and 13 seconds ago"因为它知道前3个部分没有date数据,并且忽略它们,即使指定了6个部分,也是如此不要担心:)。 当然,如果有一个段为0,则在形成string时会考虑到这一点,并将显示为"3 days and 4 seconds ago" ,忽略“0小时”部分! 享受和请评论,如果你喜欢。

  Public Function RealTimeUntilNow(ByVal dt As DateTime, Optional ByVal bAllowSegments As Byte = 2) As String ' bAllowSegments identifies how many segments to show... ie: if 3, then return string would be (as an example)... ' "3 years, 2 months and 13 days" the top 3 time categories are returned, if bAllowSegments is 2 it would return ' "3 years and 2 months" and if 6 (maximum value) would return "3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds" Dim rYears, rMonths, rDays, rHours, rMinutes, rSeconds As Int16 Dim dtNow = DateTime.Now Dim daysInBaseMonth = Date.DaysInMonth(dt.Year, dt.Month) rYears = dtNow.Year - dt.Year rMonths = dtNow.Month - dt.Month If rMonths < 0 Then rMonths += 12 : rYears -= 1 ' add 1 year to months, and remove 1 year from years. rDays = dtNow.Day - dt.Day If rDays < 0 Then rDays += daysInBaseMonth : rMonths -= 1 rHours = dtNow.Hour - dt.Hour If rHours < 0 Then rHours += 24 : rDays -= 1 rMinutes = dtNow.Minute - dt.Minute If rMinutes < 0 Then rMinutes += 60 : rHours -= 1 rSeconds = dtNow.Second - dt.Second If rSeconds < 0 Then rSeconds += 60 : rMinutes -= 1 ' this is the display functionality Dim sb As StringBuilder = New StringBuilder() Dim iSegmentsAdded As Int16 = 0 If rYears > 0 Then sb.Append(rYears) : sb.Append(" year" & If(rYears <> 1, "s", "") & ", ") : iSegmentsAdded += 1 If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn If rMonths > 0 Then sb.AppendFormat(rMonths) : sb.Append(" month" & If(rMonths <> 1, "s", "") & ", ") : iSegmentsAdded += 1 If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn If rDays > 0 Then sb.Append(rDays) : sb.Append(" day" & If(rDays <> 1, "s", "") & ", ") : iSegmentsAdded += 1 If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn If rHours > 0 Then sb.Append(rHours) : sb.Append(" hour" & If(rHours <> 1, "s", "") & ", ") : iSegmentsAdded += 1 If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn If rMinutes > 0 Then sb.Append(rMinutes) : sb.Append(" minute" & If(rMinutes <> 1, "s", "") & ", ") : iSegmentsAdded += 1 If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn If rSeconds > 0 Then sb.Append(rSeconds) : sb.Append(" second" & If(rSeconds <> 1, "s", "") & "") : iSegmentsAdded += 1 parseAndReturn: ' if the string is entirely empty, that means it was just posted so its less than a second ago, and an empty string getting passed will cause an error ' so we construct our own meaningful string which will still fit into the "Posted * ago " syntax... If sb.ToString = "" Then sb.Append("less than 1 second") Return ReplaceLast(sb.ToString.TrimEnd(" ", ",").ToString, ",", " and") End Function 

当然,你需要一个“ReplaceLast”函数,它需要一个源string和一个指定需要replace的参数,另一个arg指定要replace的参数,它只replace该string的最后一个出现…我已经包括我的一个,如果你没有一个或不想实现它,所以在这里,它将“按原样”,而不需要修改。 我知道reverseit函数不再需要(存在于.net中),但是ReplaceLast和ReverseIt函数是从before.netdate开始的,所以请原谅它的外观(仍然有100%的效果)时间超过十年,可以保证他们是无bug)… :)。 干杯。

 <Extension()> _ Public Function ReplaceLast(ByVal sReplacable As String, ByVal sReplaceWhat As String, ByVal sReplaceWith As String) As String ' let empty string arguments run, incase we dont know if we are sending and empty string or not. sReplacable = sReplacable.ReverseIt sReplacable = Replace(sReplacable, sReplaceWhat.ReverseIt, sReplaceWith.ReverseIt, , 1) ' only does first item on reversed version! Return sReplacable.ReverseIt.ToString End Function <Extension()> _ Public Function ReverseIt(ByVal strS As String, Optional ByVal n As Integer = -1) As String Dim strTempX As String = "", intI As Integer If n > strS.Length Or n = -1 Then n = strS.Length For intI = n To 1 Step -1 strTempX = strTempX + Mid(strS, intI, 1) Next intI ReverseIt = strTempX + Right(strS, Len(strS) - n) End Function 
  case TipoIntervalo.Mes: retorno = inicio.AddMonths(-fim.Month).Month.ToString(); break; case TipoIntervalo.Ano: retorno = (inicio.Year - fim.Year).ToString(); break; 

这里没有很多明确的答案,因为你总是在做假设。

这个解决scheme计算两个date之间的月份,假设你想要保存月份的date进行比较(也就是说在计算中考虑了月份中的某一天)

例如,如果您的date为2012年1月30日,则2012年2月29日将不是一个月,但2013年3月1日将是。

它已经被彻底的testing过了,可能会在我们使用它之后进行清理,并且需要两个date而不是Timespan,这可能会更好。 希望这有助于其他人。

 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 } 

如果你想要确切的数字,你不能只从Timespan,因为你需要知道你正在处理哪个月,以及你是否正在处理闰年,就像你说的那样。

要么去一个近似的数字,要么与原始的date时间做一些fidgetting

http://www.astro.uu.nl/~strous/AA/en/reken/juliaansedag.html

如果您可以将公历date转换为儒略日号码 ,您可以创build一个操作符来比较zulian日数,可以是doubletypes,以获得月,日,秒等。查看上面的内容链接从格里高利转换为朱利安algorithm。

在idiomatic-c#中没有内build的方法可以做到这一点。 有一些解决方法,例如人们编码的CodeProject示例

如果你要处理数月和数年,你需要知道每个月有多less天,哪些年份是闰年。

input公历 (和其他文化特定的日历实施)。

虽然日历不提供直接计算两个时间点之间的差异的方法,但它确实有方法

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

方法返回一个包含3个元素的列表第一个年份,第二个是月份和第二个元素是date:

 public static List<int> GetDurationInEnglish(DateTime from, DateTime to) { try { if (from > to) return null; var fY = from.Year; var fM = from.Month; var fD = DateTime.DaysInMonth(fY, fM); var tY = to.Year; var tM = to.Month; var tD = DateTime.DaysInMonth(tY, tM); int dY = 0; int dM = 0; int dD = 0; if (fD > tD) { tM--; if (tM <= 0) { tY--; tM = 12; tD += DateTime.DaysInMonth(tY, tM); } else { tD += DateTime.DaysInMonth(tY, tM); } } dD = tD - fD; if (fM > tM) { tY--; tM += 12; } dM = tM - fM; dY = tY - fY; return new List<int>() { dY, dM, dD }; } catch (Exception exception) { //todo: log exception with parameters in db return null; } } 

这是我的贡献,以获得我认为是准确的几个月的差异:

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

您可以创build另一个称为DiffYears的方法,并在while循环中应用与上述相同的逻辑和AddYears而不是AddMonths。

游戏方式晚了,但我想这可能是有帮助的人。 大多数人倾向于按月进行计算,不包括月份有不同变化的事实。 使用这个思想框架,我创build了一个比较我们date的class轮。 使用以下过程。

  1. 比较年份中的任何一年以上的年份将乘以12,不能等于不足1年的情况。
  2. 如果结束年份更大,我们需要评估当前date是否大于或等于前一天2A。 如果结束date大于或等于我们取当前月份,然后加上12个月减去开始月份2B的月份。 如果结束date小于开始date,我们执行与上述相同的操作,除了在减去前的开始月份之前加1
  3. 如果结束年度不大,我们执行与2A / 2B相同的操作,但不需要增加12个月,因为我们不需要在全年进行评估。

      DateTime date = new DateTime(2003, 11, 25); DateTime today = new DateTime(2004, 12, 26); var time = (today.Year - date.Year > 1 ? (today.Year - date.Year - 1) * 12 : 0) + (today.Year > date.Year ? (today.Day >= date.Day ? today.Month + 12 - date.Month : today.Month + 12 - (date.Month + 1)) : (today.Day >= date.Day ? today.Month - date.Month : today.Month - (date.Month + 1))); 
  DateTime dtEnd = DateTime.Now.AddDays(59); DateTime dtBegin = DateTime.Now; var diff = (dtEnd-dtBegin).TotalDays; lblDateDiff.Text = Math.Floor(diff/30).ToString() + " month('s) and " + (diff%30).ToString() + " days"; 

返回1个月(和)29天。 当然,这是依赖于月份是30天..但它是非常接近date之间的天和月的正确值。