Using and formatting DateTime and TimeSpan data types

One of the most useful constructs in the .NET Framework is the ease of use for date/time manipulation. I need to manipulate dates and time frequently, either displaying them or parsing strings containing them.

Let me show you the 5 easy ways to get a DateTime variable.

DateTime dt;
dt = DateTime.MinValue;
Console.WriteLine(dt.ToString());
dt = DateTime.MaxValue;
Console.WriteLine(dt.ToString());
dt = DateTime.Today;
Console.WriteLine(dt.ToString());
dt = DateTime.Now;
Console.WriteLine(dt.ToString());
dt = DateTime.UtcNow;
Console.WriteLine(dt.ToString());

The DateTime.MinValue represents year 0001, January 1st, on the 0th hour, the 0th minute and 0th second.

The DateTime.MaxValue represents year 9999, December 31st, on the 23rd hour, the 59th minute and 59th second.

The DateTime.Today represents today. Taking the date of this post, it’ll be year 2007, November 2nd (zeroes for the other values).

The DateTime.Now represents today with the time component. Taking the date of this post again, it’ll be year 2007, November 2nd. And (for example) the time is 9th hour, 1st minute and 34th second.

The DateTime.UtcNow represents today with the time component, in Universal Coordinated Time. Taking the date of this post again, it’ll be year 2007, November 2nd. And (for example) the time is 1st hour, 1st minute and 34th second. I’m in Singapore, so the time zone offset is 8 hours ahead of UTC.

DateTime.UtcNow is particularly useful when you deal with international data, where the dates and times can span across many countries. In this case, having one standard time offset makes manipulating and displaying dates and times easy. Then people won’t keep asking “Is this American time, or London time, or Singapore time?” Just display, and let the users add or subtract their own time zone offset to obtain data in their local time.

Specific date/time values

What if you need to create DateTime variables with a specific date and time?

DateTime dt;
// 2nd Nov 2007, 1:15 pm, 45th second, 853rd millisecond
dt = new DateTime(2007, 11, 2, 13, 15, 45, 853);
Console.WriteLine(dt.ToString());
// get the same date by parsing a string
dt = DateTime.ParseExact("20071102131545", "yyyyMMddHHmmss", null);
Console.WriteLine(dt.ToString());
// get the same date by parsing a string formatted differently
dt = DateTime.ParseExact("02/11/2007 13:15:45", "dd/MM/yyyy HH:mm:ss", null);
Console.WriteLine(dt.ToString());

I prefer using the ParseExact() function rather than Parse(). I like to have exact control over how a date/time string is interpreted, and I want any culture-specific information to be left out of the parsing. If you know exactly what you have and what you need, it’s better to do it yourself rather than letting the code do implicit conversions. I’m paranoid that way…

Displaying dates and times

Then there’s displaying them

DateTime dt;
dt = new DateTime(2007, 11, 2, 13, 15, 45, 853);
// get 2 Nov 2007 01:15 PM
Console.WriteLine(dt.ToString("d MMM yyyy hh:mm tt"));
// get November 02, 2007 13:15
Console.WriteLine(dt.ToString("MMMM dd, yyyy HH:mm"));
// get 2007-11-02T13:15:45.8+08:00
Console.WriteLine(dt.ToString("yyyy-MM-ddTHH:mm:ss.fzzz"));

The last one is in the format of the one submitted for discussion in W3 Consortium. Refer to the Microsoft documentation of date and time formats for more information.

Obtaining first and last days of the month

In my work, I’ve often had to deal with special dates, like the first and last days of the month. So how do you accomplish this?

DateTime dtStart, dtEnd;
int iDaysInMonth = 0;
dtStart = DateTime.Now;
dtStart = new DateTime(dtStart.Year, dtStart.Month, 1, 0, 0, 0, 0);
dtEnd = DateTime.Now;
iDaysInMonth = DateTime.DaysInMonth(dtEnd.Year, dtEnd.Month);
dtEnd = new DateTime(dtEnd.Year, dtEnd.Month, iDaysInMonth, 23, 59, 59, 999);
Console.WriteLine("The first day of the month is {0}", dtStart.ToString("dd/MM/yyyy HH:mm:ss"));
Console.WriteLine("The last day of the month is {0}", dtEnd.ToString("dd/MM/yyyy HH:mm:ss"));

The trick to obtaining the last day of the month is the DateTime.DaysInMonth() function. The number of days in the specific month, is also the last day of the month. No fuss, no muss.

This is way better than you implementing a custom function, which probably involves some arcane calculation with leap and non-leap years. If you do it wrongly, you’ll end up with 28 days instead of 29 for certain February’s. The DateTime.DaysInMonth() function is impervious to these mistakes.

Duration calculation with TimeSpan

Next, we have calculations of duration. This is where TimeSpan comes in. An example illustrates its use better.

DateTime dtStart, dtEnd;
dtStart = new DateTime(2007, 10, 27);
dtEnd = new DateTime(2007, 11, 2, 13, 15, 45, 853);

TimeSpan ts = dtEnd - dtStart;
Console.WriteLine(ts.Days);
Console.WriteLine(ts.Hours);
Console.WriteLine(ts.Milliseconds);
Console.WriteLine(ts.Minutes);
Console.WriteLine(ts.Seconds);
Console.WriteLine(ts.Ticks);

Console.WriteLine(ts.TotalDays);
Console.WriteLine(ts.TotalHours);
Console.WriteLine(ts.TotalMilliseconds);
Console.WriteLine(ts.TotalMinutes);
Console.WriteLine(ts.TotalSeconds);

You’ll notice 2 different sets of properties. The Days property refers to the value of TimeSpan variable for the “day” part. The TotalDays property refers to the number of days in the duration. Similarly for the other “Total”-prepended properties. Just print out the values to get a feel of the differences.

Now for a more specific and practical example. How do we calculate the number of days between two dates?

DateTime dtStart, dtEnd;
TimeSpan ts;

dtStart = new DateTime(2007, 2, 26);
dtEnd = new DateTime(2007, 3, 2);
ts = dtEnd - dtStart;
Console.WriteLine(ts.TotalDays);

dtStart = new DateTime(2008, 2, 26);
dtEnd = new DateTime(2008, 3, 2);
ts = dtEnd - dtStart;
Console.WriteLine(ts.TotalDays);

The above gives 4 days (26 Feb, 27 Feb, 28 Feb and 1 Mar) and 5 days (as before, plus 29 Feb) respectively. Note that the leap years are also taken care of. The end date is not included in the calculation. Since the end date is at the very start of the day (0th hour, 0th minute, 0th second), it’s not counted, as far as duration is concerned.

But, what if you need the number of months instead? How do you do it? Well, you don’t need TimeSpan for this…

DateTime dtStart, dtEnd;
dtStart = new DateTime(2006, 11, 15);
dtEnd = new DateTime(2007, 2, 15);
int iNumberOfMonths = (dtEnd.Year * 12 + dtEnd.Month) - (dtStart.Year * 12 + dtStart.Month);
Console.WriteLine(iNumberOfMonths);

Just because it looks like something, doesn’t mean it has to be that something

  1. Improfane

    The DateTime.MinValue represents year 0001, January 1st, on the 0th hour, the 0th minute and 0th second.

    The DateTime.MinValue represents year 9999, December 31st, on the 23rd hour, the 59th minute and 59th second.

    shouldn’t the bottom one be DateTime.MaxValue?

Comments are closed.