闰年上DateTime.AddYears的行为

时间:2012-02-29 11:27:31

标签: c# .net datetime

在DateTime上使用AddYears方法时,有人可以解释.NET中闰年计算背后的数学或原因吗?

  • 如果您参加2012年2月29日并增加一年,您将获得2013年2月28日,而非2013年3月1日(一年后的前一天)。
  • 如果您在2012年1月31日之前添加一年,则会在2013年1月31日(一年后的同一日期)到达。

我认为大多数人都会认为“从29.02起一年.leapX是01.03.leapX + 1”。

示例:

// Testing with 29th Feb
var now1 = DateTime.Parse("2012-02-29 15:00:00");

var results1 = new DateTime[]
{
    now1.AddYears(1),
    now1.AddYears(2),
    now1.AddYears(3),
    now1.AddYears(4)
};

foreach(var dt in results1)
{
    Console.WriteLine(dt.ToString("s"));
}

// Output:
// 2013-02-28T15:00:00
// 2014-02-28T15:00:00
// 2015-02-28T15:00:00
// 2016-02-29T15:00:00


// Testing with 31st Jan
var now2 = DateTime.Parse("2012-01-31 13:00:00");

var results2 = new DateTime[]
{
    now2.AddYears(1),
    now2.AddYears(2),
    now2.AddYears(3),
    now2.AddYears(4)
};

foreach(var dt in results2)
{
    Console.WriteLine(dt.ToString("s"));
}

// Output:
// 2013-01-31T13:00:00
// 2014-01-31T13:00:00
// 2015-01-31T13:00:00
// 2016-01-31T13:00:00

3 个答案:

答案 0 :(得分:13)

  

我认为大多数人都会认为“从29.02起一年.leapX是01.03.leapX + 1”。

我不会。我通常会期望截断。它基本上类似于1月30日增加一个月 - 我希望在2月份的最后一天。在这两种情况下,您都会添加一个“更大的单位”(月份或年份),而“较小的单位”(日期)将被截断以适应年/月组合。

(这就是Joda TimeNoda Time的行为方式,顺便说一下。)

正如蒂姆在评论中提到的那样,documented也是如此:

  

AddYears方法计算考虑闰年的结果年份。生成的DateTime对象的月份和时间部分与此实例保持一致。

所以必须留在二月;这一年将根据加入的年数而变化,显然 - 所以必须调整这一天才能保持有效。

答案 1 :(得分:2)

根据您的理由,2012年3月1日将成为2012年3月2日,当您增加一年时。如果您在之前的所有闰年中添加此班次,那么您将发现大量漂移的计算。唯一明智的反应是在非闰年回归28-Feb。

答案 2 :(得分:-1)

这很有趣,一点点..

例如有时会使用此功能:

private static int Age(DateTime birthDate, DateTime asAtDate)
{
    // Calculate age in years
    int age = asAtDate.Year - birthDate.Year;
    if (asAtDate < birthDate.AddYears(age)) age--;
    if (age < 0) age = 0;
    return age;
}

如果某人出生于2016年2月29日,则此功能将得出结论,他们已于2017年2月28日达到1岁。

我按照以下说明记录了Excel Function示例:

=DATEDIF(DATE(2016,2,28),DATE(2017,2,28),"Y")     
   gives result of 1
=DATEDIF(DATE(2016,2,29),DATE(2017,2,28),"Y")
   gives result of 0
=DATEDIF(DATE(2016,2,29),DATE(2017,3,1),"Y")
   gives result of 1
=DATEDIF(DATE(2016,3,1),DATE(2017,3,1),"Y")
   gives result of 1