在C#/。NET TimeSpan
中有TotalDays
,TotalMinutes
等,但我无法找出总月差异的公式。每月可变天数和闰年一直让我失望。我怎样才能获得 TotalMonths ?
修改很抱歉没有更清楚:我知道我实际上无法从TimeSpan
获得此信息,但我认为使用TotalDays
和TotalMinutes
会是一个很好的例子来表达我正在寻找的东西...除了我想要获得总月数。
示例:2009年12月25日 - 2009年10月6日= 2 TotalMonths。 10月6日至11月5日等于0个月。 11月6日,1个月。 12月6日,2个月
答案 0 :(得分:208)
您将无法从TimeSpan
获得,因为“月”是一个可变的度量单位。你必须自己计算,你必须弄清楚你希望它是如何工作的。
例如,July 5, 2009
和August 4, 2009
等日期会产生一个月或零个月的差异吗?如果你说它应该产生一个,那么July 31, 2009
和August 1, 2009
呢? 一个月?它只是日期的Month
值的差异,还是与实际的时间跨度更相关?确定所有这些规则的逻辑非常重要,因此您必须确定自己的规则并实施适当的算法。
如果你想要的只是几个月的差异 - 完全忽略日期值 - 那么你可以使用它:
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));
}
答案 1 :(得分:47)
(我意识到这是一个老问题,但是......)
在纯.NET中,这是相对的痛苦。我建议使用我自己的Noda Time库,它专为以下内容而设计:
LocalDate start = new LocalDate(2009, 10, 6);
LocalDate end = new LocalDate(2009, 12, 25);
Period period = Period.Between(start, end);
int months = period.Months;
(还有其他选择,例如,如果您只需要数月甚至数年,您就可以使用Period period = Period.Between(start, end, PeriodUnits.Months);
)
答案 2 :(得分:26)
也许你不想知道月份;这段代码怎么样?
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"
答案 3 :(得分:9)
你必须定义TotalMonths的意思。
一个简单的定义是将月份定为30.4天(365.25 / 12)。
除此之外,任何包含分数的定义似乎都没用,而更常见的整数值(日期之间的整月)也取决于非标准的业务规则。
答案 4 :(得分:8)
您需要在日期时间之外自行解决。如何处理最后的存根天数将取决于您想要使用它的目的。
一种方法是计算月份,然后在最后校正几天。类似的东西:
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;
答案 5 :(得分:7)
我在DateTime
和DateTimeOffset
上编写了一个非常简单的扩展方法来执行此操作。我希望它的工作方式与TimeSpan
上的TotalMonths
属性完全相同:即返回两个日期之间完整月份的计数,忽略任何部分月份。因为它基于DateTime.AddMonths()
,它尊重不同的月份长度并返回人类在几个月的时间段内理解的东西。
(很遗憾,您无法将其作为TimeSpan上的扩展方法实现,因为它不会保留所使用的实际日期的知识,而且几个月它们也很重要。)
代码和测试都是available on GitHub。代码非常简单:
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;
}
它通过了所有这些单元测试用例:
// 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)));
答案 6 :(得分:3)
我会这样做:
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;
}
答案 7 :(得分:3)
对此没有很多明确的答案,因为你总是在做假设。
此解决方案计算两个日期之间的月份,假设您想要保存当天的比较日期(意味着在计算中考虑当月的某一天)
例如,如果您的日期是2012年1月30日,那么2012年2月29日将不是一个月,而是2013年3月1日。
它经过了相当彻底的测试,可能会在我们使用它之后将其清理干净,并且需要两个日期而不是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
}
答案 8 :(得分:2)
case TipoIntervalo.Mes:
retorno = inicio.AddMonths(-fim.Month).Month.ToString();
break;
case TipoIntervalo.Ano:
retorno = (inicio.Year - fim.Year).ToString();
break;
答案 9 :(得分:2)
当您需要整整几个月的时间时,可接受的答案非常有用。
我需要几个月的时间。这是我花了几个月的时间才想到的解决方案:
/// <summary>
/// Calculate the difference in months.
/// This will round up to count partial months.
/// </summary>
/// <param name="lValue"></param>
/// <param name="rValue"></param>
/// <returns></returns>
public static int MonthDifference(DateTime lValue, DateTime rValue)
{
var yearDifferenceInMonths = (lValue.Year - rValue.Year) * 12;
var monthDifference = lValue.Month - rValue.Month;
return yearDifferenceInMonths + monthDifference +
(lValue.Day > rValue.Day
? 1 : 0); // If end day is greater than start day, add 1 to round up the partial month
}
我还需要一年的差异,而部分年份也同样如此。这是我想出的解决方案:
/// <summary>
/// Calculate the differences in years.
/// This will round up to catch partial months.
/// </summary>
/// <param name="lValue"></param>
/// <param name="rValue"></param>
/// <returns></returns>
public static int YearDifference(DateTime lValue, DateTime rValue)
{
return lValue.Year - rValue.Year +
(lValue.Month > rValue.Month // Partial month, same year
? 1
: ((lValue.Month = rValue.Month)
&& (lValue.Day > rValue.Day)) // Partial month, same year and month
? 1 : 0);
}
答案 10 :(得分:2)
老问题我知道,但可能对某人有所帮助。我上面已经使用了@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);
}
答案 11 :(得分:1)
This库计算月份的差异:
// ----------------------------------------------------------------------
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
答案 12 :(得分:1)
下面实际上是你可以做到的最准确的方法,因为“1个月”的定义根据它的月份而变化,而其他答案没有考虑到这一点!如果您想了解更多关于未构建到框架中的问题的信息,您可以阅读以下帖子:A Real Timespan Object With .Years & .Months (但是,阅读该帖子对于理解和使用以下功能不是必需的,它可以100%工作,没有其他人喜欢使用的近似的固有不准确性 - 并且可以随意使用您在框架上可能具有的内置.Reverse函数替换.ReverseIt函数(这只是为了完整性)。
请注意,您可以获得任意数量的日期/时间准确度,秒数和时间。分钟,秒,分钟和天,任何地方长达数年(包含6个部分/段)。如果你指定前两名并且它超过一年,它将返回“1年零3个月前”并且不会返回其余部分,因为你已经请求了两个段。如果它只有几个小时,那么它只会返回“2小时1分钟前”。当然,如果您指定1,2,3,4,5或6个分段,则适用相同的规则(最大值为6,因为秒,分钟,小时,天,月,年仅生成6种类型)。它还将纠正语法问题,如“分钟”与“分钟”,具体取决于它是否为1分钟或更长时间,对所有类型都相同,并且生成的“字符串”将始终在语法上正确。
以下是一些使用示例:
bAllowSegments标识要显示的段数...即:如果为3,则返回字符串将(例如)... "3 years, 2 months and 13 days"
(不包括小时,分钟和秒,因为前3个时间类别是但是,如果日期是较新的日期,例如几天前的某些日期,指定相同的细分(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"
的内容因为它理解前三个段中没有日期数据并忽略它们,即使你指定了6个段,所以不要担心:)。当然,如果其中有一个段为0,则在形成字符串时会考虑到这一点,并显示为"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”函数,它接受一个源字符串,一个参数指定需要替换的内容,另一个arg指定要替换它的内容,它只替换最后一次出现那个字符串...我已经包含了我的那个,如果你没有或者不想实现它,所以在这里,它将“按原样”工作,无需修改。我知道不再需要reverseit函数(存在于.net中)但是ReplaceLast和ReverseIt函数都是从pre.net时代开始的,所以请原谅它看起来多么过时(仍然可以100%使用,一直在使用em十多年来,可以保证他们没有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
答案 13 :(得分:1)
如果您想在1
和28th Feb
之间获得结果1st March
:
DateTime date1, date2;
int monthSpan = (date2.Year - date1.Year) * 12 + date2.Month - date1.Month
答案 14 :(得分:1)
几个月的问题是,这不是一个简单的衡量标准 - 它们不是一成不变的。您需要为要包含的内容定义规则,并从那里开始工作。例如1月1日至2月1日 - 你可以争辩说有2个月,或者你可以说这是一个月。那么“1月20日00:00”到“2月1日00:00” - 那不是整整一个月。那是0吗? 1?那么另一种方式(1月1日00:00至2月1日20:00)...... 1? 2?
首先定义规则,然后你必须自己编码,我害怕......
答案 15 :(得分:0)
该方法返回一个包含3个元素的列表,第一个是年份,第二个是月份,结束元素是白天:
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;
}
}
答案 16 :(得分:0)
这是我们的操作方式:
int DifferenceInMonth(DateTime startDate, DateTime endDate) {
long ToTicks(DateTime date) => new DateTimeOffset(date).Ticks;
var daysPerMonth = 30.4;
return (int)Math.Round((ToTicks(endDate) - ToTicks(startDate)) / TimeSpan.TicksPerDay / daysPerMonth);
}
答案 17 :(得分:0)
结合以上两个答案,另一种扩展方法是:
public static int ElapsedMonths(this DateTime date1, DateTime date2)
{
DateTime earlierDate = (date1 > date2) ? date2 : date1;
DateTime laterDate = (date1 > date2) ? date1 : date2;
var eMonths = (laterDate.Month - earlierDate.Month) + 12 * (laterDate.Year - earlierDate.Year) -
((earlierDate.Day > laterDate.Day) ? 1 : 0);
return eMonths;
}
感谢@AdamRobinson和@MarkWhittaker
答案 18 :(得分:0)
我对this answer的看法也使用了extension method,但它可以返回肯定或否定的结果。
public static int MonthsBefore(this DateTime dt1, DateTime dt2)
{
(DateTime early, DateTime late, bool dt2After) = dt2 > dt1 ? (dt1,dt2,true) : (dt2,dt1,false);
DateTime tmp; // Save the result so we don't repeat work
int months = 1;
while ((tmp = early.AddMonths(1)) <= late)
{
early = tmp;
months++;
}
return (months-1)*(dt2After ? 1 : -1);
}
一些测试:
// Just under 1 month's diff
Assert.AreEqual(0, new DateTime(2014, 1, 1).MonthsBefore(new DateTime(2014, 1, 31)));
// Just over 1 month's diff
Assert.AreEqual(1, new DateTime(2014, 1, 1).MonthsBefore(new DateTime(2014, 2, 2)));
// Past date returns NEGATIVE
Assert.AreEqual(-6, new DateTime(2012, 1, 1).MonthsBefore(new DateTime(2011, 6, 10)));
答案 19 :(得分:0)
计算两个日期之间的月份数:
$date1 = '2017-01-20';
$date2 = '2019-01-20';
$ts1 = strtotime($date1);
$ts2 = strtotime($date2);
$year1 = date('Y', $ts1);
$year2 = date('Y', $ts2);
$month1 = date('m', $ts1);
$month2 = date('m', $ts2);
echo $joining_months = (($year2 - $year1) * 12) + ($month2 - $month1);
答案 20 :(得分:0)
如果你想要确切的数字,你就不能只使用Timespan,因为你需要知道你正在处理的是哪个月,以及你是否正在处理闰年,就像你说的那样。
要么使用近似数字,要么使用原始日期时间进行一些操作
答案 21 :(得分:0)
比赛迟到但我想这可能对某人有所帮助。大多数人倾向于按日期逐月测量,不包括月份有不同变化的事实。使用这种思想框架,我创建了一个衬垫,用于比较我们的日期。使用以下过程。
如果结束年份不是更大,我们执行与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)));
答案 22 :(得分:0)
以下是我在几个月内找到准确差异的贡献:
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。
答案 23 :(得分:0)
如果您要处理数月和数年,您需要知道每个月有多少天以及哪些年是闰年。
输入Gregorian Calendar(以及其他特定于文化的Calendar实施)。
虽然日历不提供直接计算两个时间点之间差异的方法,但它确实有
等方法DateTime AddWeeks(DateTime time, int weeks)
DateTime AddMonths(DateTime time, int months)
DateTime AddYears(DateTime time, int years)
答案 24 :(得分:0)
http://www.astro.uu.nl/~strous/AA/en/reken/juliaansedag.html
如果您可以将从格里高利日期转换为Julian day number的时间,您可以创建一个运算符来比较zulian日数,这可以是double类型以获得月,日,秒等查看上面的链接,了解从格里高利转换为朱利安的算法。
答案 25 :(得分:0)
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;
答案 26 :(得分:0)
在idiomatic-c#中没有内置的方法可以准确地做到这一点。有一些解决方法,例如人们编码的this CodeProject example。
答案 27 :(得分:-1)
接受的答案非常不正确:
对于这些日期:ldate = 2020-08-30 和 rdate = 2020-08-01,我们有一个月,但接受的答案返回 0。
对于这些日期:ldate = 2020-08-30 和 rdate = 2020-10-01,我们有三个月,但接受的答案返回 -2。
这是计算两个日期之间的月数的正确方法(可能不是唯一的方法,但正确):
您不必检查哪个日期低于其他日期。
从一个月的第一天到最后一天的间隔算作一个月。
public static int GetMontsBetween(DateTime date1, DateTime date2)
{
int monthCount = 0;
int direction = date1 < date2 ? 1 : -1;
date2 = date2.AddDays(direction);
while (date1.Year != date2.Year || date1.Month != date2.Month)
{
date1 = date1.AddMonths(direction);
monthCount++;
}
return monthCount;
}