Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Behavior of DateTime.AddYears on leap year

Tags:

c#

.net

datetime

Can anyone explain the mathematical or simply the reasoning behind the leap year calculations in .NET when using AddYears method on DateTime?

  • If you take the 29th Feb 2012 and add a year, you get the 28th Feb 2013, not the 1st Mar 2013 (day before one year later).
  • If you add one year to 31st Jan 2012, you get 31st Jan 2013 (same date one year later).

I think most people would assume that "one year from 29.02.leapX is 01.03.leapX+1".

Example:

// 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
like image 996
krembanan Avatar asked Feb 29 '12 11:02

krembanan


1 Answers

I think most people would assume that "one year from 29.02.leapX is 01.03.leapX+1".

I wouldn't. I would normally expect truncation. It's fundamentally similar to adding one month to January 30th - I'd expect to get the last day in February. In both cases, you're adding a "larger unit" (month or year) and a "smaller unit" (day) is being truncated to fit in with the year/month combination.

(This is how Joda Time and Noda Time behave too, btw.)

As Tim mentioned in comments, it's documented that way too:

The AddYears method calculates the resulting year taking into account leap years. The month and time-of-day part of the resulting DateTime object remains the same as this instance.

So the month has to stay as February; the year will change based on how many years are being added, obviously - so the day has to adjust to stay valid.

like image 126
Jon Skeet Avatar answered Sep 20 '22 19:09

Jon Skeet