Adding Emptiness to the DateTime class


I got an interesting email from a customer today, asking for my opinion on how to deal with the concept of “Empty” in relation to DateTime values. They had decided to use the DateTime.MinValue value as an indication that the DateTime was empty.


The two options they were consider were:


1) Call static functions to determine whether a DateTime is empty
2) Just compare the DateTime value to DateTime.MinValue to see if it is empty.


After a bit of reflection, I decided that I didn’t like either approach. The problem is that they’re trying to add a new concept of “emptiness” (some might equate this to “null”) to a type without changing the type.


A better approach is to define a new type that supports the concept of emptiness. In this case, we’ll create a struct that encapsulates the DateTime value and lets us deal with empty in a more robust manner.


Here’s the struct I wrote for them (and, no, this is not an indication that I’m now writing classes when people ask me to). 

public struct EmptyDateTime
{
DateTime dateTime;

public EmptyDateTime(DateTime dateTime)
{
this.dateTime = dateTime;
}

public bool IsEmpty
{
get
{
return dateTime == DateTime.MinValue;
}
}

public static explicit operator DateTime(EmptyDateTime emptyDateTime)
{
if (emptyDateTime.IsEmpty)
throw new InvalidOperationException(“DateTime is Empty”);
return emptyDateTime.dateTime;
}

public static implicit operator EmptyDateTime(DateTime dateTime)
{
return new EmptyDateTime(dateTime);
}

public static EmptyDateTime Empty
{
get
{
return new EmptyDateTime(DateTime.MinValue);
}
}
}

Comments (29)

  1. Jon Galloway says:

    Agree, this is a nice approach to this problem. This has been taken a bit further by the NullableTypes project: http://nullabletypes.sourceforge.net/

  2. Of course, they wouldn’t need this hack if value types were nullable. 🙂

  3. If you are going to all the effort of creating a new class, why not use an extra bool instead of DateTime.MinValue?

  4. How will this integrate with third party UI controls?

  5. Steven,

    You could use an extra bool instead of a specific value, if you were willing for your types to be bigger.

    That may be a reasonable tradeoff in some situations.

    Thomas, the answer to your question is probably "not too well".

  6. Keith Patrick says:

    I’m not really fond of the name, though, as the struct isn’t necessarily empty; it’s empty-able, although a better name escapes me

  7. RichB says:

    A library I wrote a couple of years ago requires each component of a Date to be undeclared – eg 5th May, unknown year – or 5th May, year 2001 or 2002 or 2003

    The only way to handle this was to create a wrapper around a date.

    BTW – any chance of extending the date class to support BC dates rather than AD (CE) dates? And any chance of WinForms supporting the whole range of DateTime dates in it’s calendar control, rather than stopping at the OLE limit?

  8. Jocelyn Coulmance says:

    What about System.Data.SqlTypes.SqlDateTime ?

    Isn’t it what it’s all about ?

  9. In our company we use an approach that was published in the Visual Basic Programmer’s Journal in 2000. The article is availabe online via MSDN at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvbpj00/html/nullvalues.asp

    The idea is called the "Alias Null concept", where a constant value acts as a surrogate for a database NULL value.

    We have implemented a utility class NullValue that offers operations like bool IsNullAlias(object val) to check, if a current value is a Null Alias. Our windows forms data binding takes care of this, so database NULL values will be displayed correctly.

    Our persistence framework converts database NULL values into Alias Nulls when reading data in and writes database NULL values into the database when properties of persistent objects have an Alias Null value. Works pretty well for us.

  10. I did like Eric but took Sql Server’s MinDate instead of DateTime.MinDate.

  11. Johnny Hall says:

    SqlTypes are not serializable (AFAIK). They’re also bound to SQL Server (duh!), which is no use if you need to use another DB.

  12. I have to admit, I don’t like this issue either. This is probably the only thing that irks me when it comes to dealing with value types.

    I can’t admit to having a solution (having a new type that encapsulates the value type doesn’t seem right, unless it is provided in the System namespace).

    Also, implementing INullable on value types doesnt seem like it would work either.

    For the solution you provided, you should have implemented INullable for completeness.

    Also, you could have recommended that they use the SqlDateTime structure, whcih provides null semantics.

  13. Paul Tyng says:

    I have done something similar in my own business objects. The next step for your own nullable type is to implement IComparable so that you can sort on this column and IConvertible will allow you to pass this type directly to command objects and the like.

    Of course for databinding for a property named BornOn of class Budweiser, binding will look for a property called BornOnIsNull to determine if its null or not, so going forward I’ve come to the conclusion that I should not expose my custom nullable types outside of my business objects, just use them internally.

    Paul

  14. Paul Tyng says:

    Nicholas: IConvertible lets a value type tell a command object its DBNull.Value.

  15. ÿ says:

    Dietmar,

    The http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvbpj00/html/nullvalues.asp is talking about VB 5/6 – in which this isn’t really a major issue, since you would just use a Variant (which can handle Null).

    Seeya

  16. Matt says:

    Make you yearn for a generic called Nullable<T>. 😉

  17. Thomas Eyde says:

    So why is DateTime sealed?

    This would do the trick if it weren’t:

    public class EmptyDateTime : DateTime

    {

    private EmptyDateTime() {}

    public static EmptyDateTime Empty;

    }

    I have not worked with value types, so it could be the singelton pattern doesn’t work here, or the Equals method must be overridden.

  18. Sergio Acosta says:

    I like the solution, but that name of ‘EmptyDateTime’ is quite ugly and missleading.

    It should’ve been NullableDateTime or something like that.

  19. Cliff says:

    What about adding NAD to DateTime?

  20. Mirko Geffken says:

    Or you could just hold your breath for another 8 mo. or so and use .NET 2.0 with their nullable types (or jump into the beta):

    DateTime? dt=new DateTime();

    and then

    if (dt.HasValue)

    {

    }