Using nullable types and extension methods for the DateTime of your life
February 6, 2009We’ve all been through this before: You’ve got a DateTime type in your code that you need to populate from a database which allows null DateTime values. What do you do?
Magic values
For the longest time I had used the “magic value” approach, which was to interpret DateTime’s default value (DateTime.MinValue) to indicate that it had been null in the database. This was fine since I’ve never come across an instance where 1/1/0001 would ever have been valid, but it was a huge pain the ass when it came to display time. It always required checking the value first and outputting a string that either represents a valid date, or one that represents an invalid one.
I typically bind business objects to Repeater controls and have always, always wanted to be able to do something so simple and basic as this…
<%# Eval("MyDateTimeProperty").ToString("MM/dd/yyyy") %>
…and have it either render a string such as 02/08/2009 when it was “valid” or simply render an empty string when when it wasn’t. No checking values, no logic, just a ToString() that works as I would expect.
Object wrappers
So finally I got smart (or so I thought at the time) and created a custom date class that had a private member variable of DateTime, and the class dealt with all of this nonsense on it’s own. I overrode ToString() and created ToString(string format) methods that returned the appropriate string output depending on whether the internal DateTime member variable equaled DateTime.MinValue or not.
The above code snippet would have worked just fine in this case, but it required changing all my DateTime references to actual MyCustomDateTime references, not only making my code a bit more confusing for others, it was adding additional performance overhead as all of these types now were being stored as objects in the heap.
Enter Nullable Types
Turn’s out I wasn’t really smart at all because if I was, I would have realized that this is such an incredibly common problem, C# might already have a built-in solution for it. Indeed, with the introduction of Nullable Types in C# 2.0, there is.
//creating a nullable DateTime, the long way Nullable<DateTime> someDate = null; //creating a nullable DateTime, short-hand DateTime? someOtherDate = null;
This will compile and work! All you have to do is declare a Nullable DateTime type and you’re in business, and with a little syntactic sugar, all that requires is adding a “?” to the end of your type declaration!
Not so fast…
<%# Eval("MyNullableDateTimeProperty").ToString("MM/dd/yyyy") %>
…Doesn’t work now. While the default ToString() method is available to a Nullable Type of DateTime (it will return an empty string when it is null), there is no longer an option to specify a format string, or any other methods you are accustomed to seeing with DateTime, such as ToShortDateString().
The actual underlying DateTime type is accessed through the Value property of the Nullable Type instance, so you can get to it and use any of the methods contained in DateTime like so:
DateTime? someDate = DateTime.Now; someDate.Value.ToShortDateString();
But of course, this requires our DateTime value to be non-null, else this will cause an exception. It looks like we still need to have some sort of way to call a ToString(string format) like method on the actual Nullable Type instance that can perform the logic to determine whether it’s value is null or not, and act appropriately.
Extension methods have joined the party
With Extension Methods, we can complete the last piece of the puzzle and actually add the ToString(string format) functionality directly to the Nullable DateTime type.
namespace MyExtensions
{
public static class Extensions
{
public static string ToString(this DateTime? dateTime, string format)
{
if (dateTime.HasValue)
return dateTime.Value.ToString(format);
else
return "";
}
}
}
With this Extension method defined above, you will now be able to call .ToString(string format) directly on your Nullable DateTime types and it will either return the actual DateTime formatted according to the format string, or it will return a blank string.
I’ve elaborated on this Extension method a bit further and Included an overload that allows you to specify the string you want to be returned if the DateTime is null. I’ve also included a ToShortDateString() method that does the same as the one within DateTime, only because I commonly use that method in my own code.
namespace MyExtensions
{
public static class Extensions
{
public static string ToString(this DateTime? dateTime, string format)
{
return dateTime.ToString(format, "");
}
public static string ToString(this DateTime? dateTime, string format, string returnIfNull)
{
if (dateTime.HasValue)
return dateTime.Value.ToString(format);
else
return returnIfNull;
}
public static string ToShortDateString(this DateTime? dateTime)
{
return dateTime.ToShortDateString("");
}
public static string ToShortDateString(this DateTime? dateTime, string returnIfNull)
{
if (dateTime.HasValue)
return dateTime.Value.ToShortDateString();
else
return returnIfNull;
}
}
}
Tags: nullable types, datetime, extension method
Categories: ASP.NET, C#