Tuesday 13 March 2012

The Leap Day Bug !!!

No no...the title is not wrong it is indeed 'Leap Day Bug' and not 'Leap Year Bug'.

There was nothing challenging about this issue but the date on which this surfaced gave it the honor of getting listed on the blog :)

29th February 2012

That the day was 29th did not go unnoticed as one of my cousin's birthday falls on this day. Other than that there was nothing special about the day but thanks to this issue I now have something to add to the leap year conversations.

I had to go to Baner office for attending a technical presentation. Few minutes into the presentation and there was an email from one of the developer from other team regarding the product installation failure. The developer had trouble installing even the old product builds which he had installed previously. After some time another developer reported the same issue. By lunch time there were flurry of emails from other teams as well as QAs regarding issue with product installation.

On returning to the Godrej office, the first I did was to have a look at one of the QA scenarios where the product installation failed. Of course, one thing was continuously on mind as to why suddenly the product was not in a mood to get installed :)

Following was the exception in the product log:


System.ArgumentOutOfRangeException: Year, Month, and Day parameters describe an un-representable DateTime.
   at System.DateTime.DateToTicks(Int32 year, Int32 month, Int32 day)



Did the above exception ring a bell? It indeed.

I had seen this error two days back and had also created a sample application to reproduce the issue but to no avail. However, running the same sample application greeted me with a pleasant surprise and the surprise is not hard to guess. Yes, the sample application also threw same exception. So, half the battle was won by reproducing the issue with sample application. Next step was to find out the root cause.

The code that was failing was written to get the expiration date time by adding the provided N years to current date time. Following snippet should give some idea about the code:









After going through the code again and keeping in mind the ArgumentOutOfRangeException, it was no more than a child's play to put all the pieces of the puzzle together.

The above code does following:
  1. Take today's date time
  2. Create a new DateTime object using the constructor which takes
    • Year
    • Month
    • Day
  3.  Take difference and return number of days
The culprit was step #2 i.e. the first parameter to constructor. If you noticed, the input N years was being added to current date's year i.e. on 29th Feb. 2012 this would make the value as 2012 + N.

Now, in the product installation the default value for N was 25, which means 2012 + 25 = 2037. So, on 29th Feb. 2012 we were trying to create a DateTime object with year as 2037, month as 02 and day as 29 i.e. the new date being 29th Feb. 2037. This will always throw ArgumentOutOfRangeException because there is no 29th Feb. in the year 2037 as it won't be a leap year :)

Fix
The fix was just to use the provided AddYears() function on the DateTime object. Yes, a single line fix :)

Workaround
While you are working on the fix the first thing to do is to see if others can be unblocked by providing a workaround. In this case the workaround was simple. The default value of 25 years was to be changed to 24 or any value which when added to 2012 would result in a leap year. With this workaround, the product installation was successful.

Epilogue
If you remember I had mentioned that the sample application for this issue was created two days back. This was because a QA had reported same issue with same error on 27th. Feb. That time I had created the sample application but it did not throw the exception on my machine as the date time was 27th Feb. But when I checked the system time on QA scenario it showed 29th Feb. Since I had other issues to look at I did not bother to see if the sample application would fail by changing the date to 29th. Instead I asked the QA to change the system time properly to 27th which solved the issue on QA scenario. Little did I know that the issue would resurface on a large magnitude on the auspicious day of 29th Feb. 2012 :)

No comments:

Post a Comment