Introduction
Occasionally you run into a structure in the .NET library that you really wish was a class so you can inherit all its existing properties, override the ones you don't like, and add new properties and methods. Such a class is the DateTime class. Here I was sitting and writing some monitoring software and I wanted to re-assign a few of the properties of my DateTime class.
Let me give you the scenario.I wanted to create a DateTime with today's date and manipulate the time within the date. Seems simple enough, right? Here is what I found I needed to do.
Listing 1. Creating a time with today's date using two DateTime's
DateTime dt1 = DateTime.Now;
DateTime dt2 = new DateTime(dt1.Year, dt1.Month, dt1.Day, 9, 30, 0, 0);
So I needed two date times to complete my mission. I suppose I could have done the following
Listing 2. Creating a time with today's date using many DateTime.Now's
DateTime dt = new DateTime(DateTime.Now.Year,DateTime.Now.Month, DateTime.Now.Day, 9, 30, 0, 0);
But I suspect this an expensive call with all the DateTime.Now's in there. What would be ideal would be able to create a single DateTime class and assign it the hours, minutes, etc. that it needs. When I tried to assign values to Hours and Minutes properties, I soon found out that were read only.
Listing 3. Illegal version of assigning hours and minutes to a DateTime with today's date
DateTimeExtended dt = DateTime.Now;
dt.Hour = 6;// illegal, read-only property
dt.Minute = 59; // illegal, read-only property
In order to accomplish what I really wanted to do, I created a new class called DateTimeExtended. Because DateTime is a structure, the only way to glom the properties of DateTime is to create an aggregate member of the DateTimeExtended class that is a DateTime type. Then you need to propagate the DateTime properties up through the DateTimeExtended class.
Figure 1. UML Design of the DateTimeExtended class reverse engineered using WithClass
All I had to do now was override a few constructors and propagate the properties in which I'm interested. So how do I go about making Hour, Minute, and Second assignable? I want to leverage the DateTime object inside my DateTimeExtended class and encapsulate all the workarounds inside the class so as not to confuse the user. Below is the Hour property of the DateTime class. Note that I took advantage of the AddHours method to accomplish my goal of assigning the Hour property. This exact same technique is used for all the other DateTime properties (Year, Month, Day, Minute, Millisecond, etc.).
Listing 4. Propogating an assignable Hour property from the DateTime class
public int Hour
{
get
{
return _val.Hour; // just propogate the
// DateTime property here
// for the get
}
set
{
// the set is a bit more complicated.....
// first subtract off existing hours
_val = _val.Subtract(new TimeSpan(_val.Hour, 0, 0));
// then add back your assigned hours
_val = _val.AddHours(value);
}
}
Listing 4 gives you the idea of how I can propagate any existing methods or properties of the DateTime class and use them however I wish. Another example is propagating the powerful and formattable ToString method of the DateTime class shown in listing 5.
Listing 5. propagating the ToString method for formatting date time strings
public string ToString(string format)
{
return _val.ToString(format); // just propagate to
// the DateTime class
}
Since DateTimeExtended is simply a subset of DateTime, you can also create a static method that allows you to implicitly assign a DateTimeExtended object to a DateTime object. This way the compiler will automatically allow the conversion without the explicit (DateTime) prefix whenever you reference it to a DateTime type.
Listing 6. Implicit conversion from DateTimeExtended to DateTime
// implicitly conversion from DateTimeExtended to DateTime. returns
// the internal DateTime
public static implicit operator DateTime(DateTimeExtended x)
{
return x._val;
}
By utilizing a constructor of the DateTimeExtended class we can also do an implicit conversion in the other direction. Another word, we can assign a DateTimeExtended class to a DateTime class:
Listing 7. Implicit conversion from DateTime to DateTimeExtended
// Implicit Conversion from DateTime to DateTimeExtended
// creates a new DateTimeExtended and returns it
public static implicit operator DateTimeExtended(DateTime x)
{
// Construct a date time extended class from a DateTime
DateTimeExtended dt = new DateTimeExtended(x);
return dt;
}
// constructor for constructing a DateTimeExtended
// class from a DateTime class
public DateTimeExtended(DateTime dt)
{
_val = dt;
}
Implementing the DateTimeExtended Class
Now we can do what we originally set out to do. We can create a DateTimeExtended class with today's date and assign it the time properties we wish. Below is a method demonstrating how to use the DateTimeExtended class to do just that. The method creates a new DateTimeExtended with today's date. It prints the original time and date out to the console. It assigns a new time to the DateTimeExtended object, and it writes out the new time to the console using the special datetime formatting capability.
Listing 8. Demonstrating the DateTimeExtended class by assigning a new Time through its properties
/// <summary>
/// Demonstrates using the DateTimeExtended class
/// </summary>
public void Show()
{
// Assign the DateTimeExtended class implicitly
// with today's date
DateTimeExtended assignableDateTime = DateTime.Now;
// write the initial time to the console
Console.WriteLine("The time is {0}", assignableDateTime.ToString("MMM-dd h:mm"));
// assign a new time to hours and minutes
assignableDateTime.Hour = 6;
assignableDateTime.Minute = 59;
// write the new time to the console
Console.WriteLine("The time is now {0}",
assignableDateTime.ToString("MMM-dd h:mm"));
}
References
Here are some more articles on DateTime you may want to check out.