Now where did I put that day? .NET Date Math, and Reversibility
This past week, I hit an interesting quirk with dates in .NET (or possibly it’s a quirk with the Gregorian calendar). I started by subtracting 6 months from "today" to get a new date, and then later would add 6 months back to make sure I would get "today" again. This scenario was part of a very simple unit test that I had written weeks ago, and had been passing fine for all of that time.
That is, until "today" was 8/29/2013. On that day, my test failed.
If "today" were 8/15/2013, then subtracting 6 months would yield 2/15/2013 – just what I’d expect;
DateTime InitialDate, NewDate; InitialDate = DateTime.Parse("8/15/2013"); NewDate = InitialDate.AddMonths(-6); // NewDate will be 2/15/2013
However, if I started with 8/29/2013, there’s a snag:
DateTime InitialDate, NewDate; InitialDate = DateTime.Parse("8/29/2013"); NewDate = InitialDate.AddMonths(-6); // NewDate will be 2/28/2013
There is no 29th day of February in 2013, so to return a valid date .NET returns 2/28/2013 instead. What happens when I add 6 months to 2/28/2013?
DateTime InitialDate, NewDate; InitialDate = DateTime.Parse("2/28/2013"); NewDate = InitialDate.AddMonths(6); // NewDate will be 8/28/2013
I get 8/28/2013 – not what I originally started with. I actually end up losing a day due to the equivalent of a rounding error for calendars.
What if I were to go in the other direction originally – start with 8/29/2013 and ADD 6 months?
DateTime InitialDate, NewDate; InitialDate = DateTime.Parse("8/29/2013"); NewDate = InitialDate.AddMonths(6); // NewDate will be 2/28/2014
As before, since February 2014 has no 29th day, .NET gives me the next oldest day – the 28th.
The lesson here is that date-math using MONTHS is not always a reversible operation. If I were to switch to adding and subtracting DAYS, however, that appears to be reversible:
DateTime InitialDate, NewDate; InitialDate = DateTime.Parse("8/29/2013"); NewDate = InitialDate.AddDays(-183).AddDays(183); // NewDate will be 8/29/2013
This isn’t limited to February, either. Any time my starting month has more days than the month I end up with, this will happen (for example, October and April, December and June).
Ah, fun with dates.