Heres a complete method, weeks are not included, but could be added relatively simply. It's a somewhat complex question (asked in a multitude of ways on stackoverflow and answered poorly in a multitude of ways), but none the less can be answered. The TimeSpan object gives us part of what we need, but only works up through days. I've written a significant number of tests against this method, if you find a hole, please post a comment.
What this will do is compare 2 dates, getting the years, months, days, hours, and minutes. (e.g. some event happened 1 year, 6 months, 3 days, 4 hours and 7 minutes ago)
Because this question has been asked and attempted to be answered so many times, I'm not sure this will ever even get noticed, but if so it should provide value.
public static void TimeSpanToDateParts(DateTime d1, DateTime d2, out int years, out int months, out int days, out int hours, out int minutes)
{
if (d1 < d2)
{
var d3 = d2;
d2 = d1;
d1 = d3;
}
var span = d1 - d2;
months = 12 * (d1.Year - d2.Year) + (d1.Month - d2.Month);
//month may need to be decremented because the above calculates the ceiling of the months, not the floor.
//to do so we increase d2 by the same number of months and compare.
//(500ms fudge factor because datetimes are not precise enough to compare exactly)
if (d1.CompareTo(d2.AddMonths(months).AddMilliseconds(-500)) <= 0)
{
--months;
}
years = months / 12;
months -= years * 12;
if (months == 0 && years == 0)
{
days = span.Days;
}
else
{
var md1 = new DateTime(d1.Year, d1.Month, d1.Day);
// Fixed to use d2.Day instead of d1.Day
var md2 = new DateTime(d2.Year, d2.Month, d2.Day);
var mDays = (int) (md1 - md2).TotalDays;
if (mDays > span.Days)
{
mDays = (int)(md1.AddMonths(-1) - md2).TotalDays;
}
days = span.Days - mDays;
}
hours = span.Hours;
minutes = span.Minutes;
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…