我的答案并不完全是答案;这是一种在此线程和类似线程中找到答案的方法。 LukeH 已经提供了正确答案,并且
我的 2 美分是给任何想知道哪个是更正确答案的人*。
*更正确,因为正如您在分散的几次讨论和 cmets 中看到的,我们必须在闰年妥协一些先决条件 - 正常年份的 dob 是 3 月 1 日还是 2 月 28 日?
我将 this 和 this other 用作基准测试的网站,我的大脑也是如此;)
我在这里实现了 LukeH、@Panos Theof 和 @xr280xr 的答案:
public static class DateTimeExtensions
{
public static int HowOld(this DateTime initialDay, DateTime dayToCalculate, out int days, out int months)
{
//https://stackoverflow.com/a/3055445/2752308
//LukeH: essentially right
months = dayToCalculate.Month - initialDay.Month;
int years = dayToCalculate.Year - initialDay.Year;
if (dayToCalculate.Day < initialDay.Day)
{
months--;
}
if (months < 0)
{
years--;
months += 12;
}
days = (dayToCalculate - initialDay.AddMonths((years * 12) + months)).Days;
Console.WriteLine(
$"{years} year{((years == 1) ? "" : "s")}, {months} month{((months == 1) ? "" : "s")} and {days} day{((days == 1) ? "" : "s")}");
return years;
}
public static int HowOld2(this DateTime initialDay, DateTime dayToCalculate, out int days, out int months)
{
//@Panos Theof: wrong
months = dayToCalculate.Month - initialDay.Month;
int years = dayToCalculate.Year - initialDay.Year;
if (dayToCalculate.Day < initialDay.Day)
{
dayToCalculate = dayToCalculate.AddMonths(-1);
}
if (months < 0)
{
dayToCalculate = dayToCalculate.AddYears(-1);
months += 12;
}
years = dayToCalculate.Year - initialDay.Year;
var offs = initialDay.AddMonths(years * 12 + months);
days = (int)((dayToCalculate.Ticks - offs.Ticks) / TimeSpan.TicksPerDay);
Console.WriteLine(
$"{years} year{((years == 1) ? "" : "s")}, {months} month{((months == 1) ? "" : "s")} and {days} day{((days == 1) ? "" : "s")}");
return years;
}
public static int HowOld3(this DateTime initialDay, DateTime dayToCalculate, out int days, out int months)
{
//@xr280xr: wrong
//Get the relative difference between each date part
days = dayToCalculate.Day - initialDay.Day;
months = dayToCalculate.Month - initialDay.Month;
int years = dayToCalculate.Year - initialDay.Year;
if (days < 0)
{
days = DateTime.DaysInMonth(initialDay.Year, initialDay.Month) - initialDay.Day + //Days left in month of birthday +
dayToCalculate.Day; //Days passed in dayToCalculate's month
months--; //Subtract incomplete month that was already counted
}
if (months < 0)
{
months += 12; //Subtract months from 12 to convert relative difference to # of months
years--; //Subtract incomplete year that was already counted
}
Console.WriteLine(string.Format("{0} year{1}, {2} month{3} and {4} day{5}",
years, (years == 1) ? "" : "s",
months, (months == 1) ? "" : "s",
days, (days == 1) ? "" : "s"));
return years;
}
}
使用 VS2019 和 XUnit 我创建了一个内联数据生成器类:
public class CalculatorTestData : IEnumerable<object[]>
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { new DateTime(1966, 7, 27), new DateTime(2020, 7, 26), 53, 11, 29 };
yield return new object[] { new DateTime(1966, 7, 27), new DateTime(2020, 7, 27), 54, 0, 0 };
yield return new object[] { new DateTime(1966, 7, 27), new DateTime(2020, 7, 28), 54, 0, 1 };
yield return new object[] { new DateTime(1968, 2, 29), new DateTime(2020, 2, 28), 51, 11, 30 };
yield return new object[] { new DateTime(1968, 2, 29), new DateTime(2020, 2, 29), 52, 0, 0 };
yield return new object[] { new DateTime(1968, 2, 29), new DateTime(2020, 3, 01), 52, 0, 1 };
yield return new object[] { new DateTime(2016, 2, 29), new DateTime(2017, 2, 28), 0, 11, 30 };
}
IEnumerator<object[]> IEnumerable<object[]>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
并设置三种方法:
[Theory]
[ClassData(typeof(CalculatorTestData))]
public void TestHowOld(DateTime initialDay, DateTime dayToCalculate,int expectedYears, int expectedMonths, int expectedDays)//, out int days, out int months
{
//LukeH: essentially right
int resultMonths, resultDays;
int age = initialDay.HowOld(dayToCalculate,out resultDays,
out resultMonths); //https://stackoverflow.com/questions/28970265/how-to-test-method-with-out-parameters
Assert.Equal(age, expectedYears);
Assert.Equal(resultMonths, expectedMonths);
Assert.Equal(resultDays, expectedDays);
}
[Theory]
[ClassData(typeof(CalculatorTestData))]
public void TestHowOld2(DateTime initialDay, DateTime dayToCalculate, int expectedYears, int expectedMonths, int expectedDays)//, out int days, out int months
{
//@Panos Theof: wrong
int resultMonths, resultDays;
int age = initialDay.HowOld2(dayToCalculate, out resultDays,
out resultMonths); //https://stackoverflow.com/questions/28970265/how-to-test-method-with-out-parameters
Assert.Equal(age, expectedYears);
Assert.Equal(resultMonths, expectedMonths);
Assert.Equal(resultDays, expectedDays);
}
[Theory]
[ClassData(typeof(CalculatorTestData))]
public void TestHowOld3(DateTime initialDay, DateTime dayToCalculate, int expectedYears, int expectedMonths, int expectedDays)//, out int days, out int months
{
//@xr280xr: wrong
int resultMonths, resultDays;
int age = initialDay.HowOld3(dayToCalculate, out resultDays,
out resultMonths); //https://stackoverflow.com/questions/28970265/how-to-test-method-with-out-parameters
Assert.Equal(age, expectedYears);
Assert.Equal(resultMonths, expectedMonths);
Assert.Equal(resultDays, expectedDays);
}
当然,预期的结果是在 InlineData 类上。
输出结果为:
所以,LukeH 有正确的答案。而且,令我惊讶的是,两个网站都不同意跳跃 DOB,恕我直言 Calculator.net 是正确的,而 timeanddate.com 显然是错误的,产生了这个错误输出:
2 月 29 日出生日期:
-
28/02 和 29/02 都产生 52, 0, 0 (?!)
-
01/03 产生 52、0、2 (!!!???)
-
2016 年 2 月 29 日 => 2017 年 2 月 28 日 => 1 岁,0 米,1 天(!!!???)
希望展示测试设置对某人有所帮助。