Monday, April 14, 2008

Bug in DateTime.TryParse and/or DateTime.CompareTo

Today I stumbled over what can only be described as a bug in the DateTime.TryParse function in C#.

Consider the following code (useless but to prove a point);

 

DateTime myDate = DateTime.MaxDate;

DateTime myParsedDate = DateTime.MinDate

if (DateTime.TryParse(myDate, out myParsedDate)

{

// We have a valid date (of course)

if (myDate.CompareTo(myParsedDate) == 0)

{

//  Surely the two dates are still the same

MessageBox.Show("The dates are the same");

}

}

 

Now this pointless code, would surely display a message box with "The dates are the same" on it...right?

Wrong!

It turns out, that the myParsedDate variable will contain as a result of the call to DateTime.TryParse will be minutely different to what was sent in, in myDate.

The value of myDate.Ticks, before and after the TryParse call is : 3155378975999999999

BUT:

The value of myParsedDate.Ticks, before the TryParse is 0 (irrelevant) but after the TryParse call, it is 3155378975000000000

The difference between myParsedDate and myDate, after the TryParse function is called, is 999,999,999 ticks or 99,999,999,900 nanoseconds = 99.9999999 seconds.

Now come the year 9999, the Y10K bug is probably going to present bigger problems than a missing 1 minute and 40 seconds - but to the DateTIme.CompareTo function, right now in 2008, those missing 100 seconds are quite important.

So a non-zero value is returned form the CompareTo function and the code does not get executed.

To work around this, I call the TryParse function, as I still need to ensure I have a valid date (even though in the example above, you can be pretty sure of that), but rather than rely on the value in the "out" parameter (myParsedDate) I explicitly assigned it as follows:

DateTime myDate = DateTime.MaxValue;

DateTime myParsedDate = DateTime.MinValue

if (DateTime.TryParse(myDate, out myParsedDate)

{

// We have a valid date (of course)

// Explicitly assign the date so that CompareTo will work

myParsedDate = myDate;

if (myDate.CompareTo(myParsedDate) == 0)

{

//  Surely the two dates are still the same

MessageBox.Show("The dates are the same");

}

}

A pointless exersice here, to be sure, but my real world example revolved around obtaining a value from a property of an object using a PropertyInfo object and the GetValue call, which returns an object. That object had to be testing to see if it contained a valid date. I also wanted to only display values that were not DateTime.MaxValue so I had to be able to compare the result that was found, after validating it (TryParse) with MaxValue - reliably...