Difference in months between two dates
如何计算c_中两个日期之间的月份差异?
C中是否有与VB的
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。
这里有一个全面的返回
用途:
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
为了方便起见,我将逻辑集中到
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。
要获得月份差异(包括开始和结束),不考虑日期:
1 2 3 |
我只需要一些简单的事情来满足,例如,只输入月份/年份的就业日期,所以需要不同的年份和月份。这是我用的,这里只是为了有用
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 |
(示例来源)
可以使用.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(); |