Follow Me On Twitter Facebook LinkedIn Flickr
Surprisingly I'm rather liking the Amazon elastic compute cloud. Running my first VM instance with my new pet Linux distro ubuntu 10.04 ... 3 weeks ago
A software development and computer technology blog.

Archive for July, 2006

It’s a Date!

There’s one aspect of programming that has always given me cause to spout prolific expletives and yet it’s something that is required in most applications. I am of course talking about Date handling.

If I had my way then everyone would use a format which, like number systems, book contents pages and many other structures in everyday life, starts with the largest denomination or unit down to the smallest. I.e. Year Month Day Hour Minute Second, using whichever separator is preferred and unit format, e.g. ’2006-JAN-21 12:15:34′, ’06/01/21′, ’2006, January 15th’, etc.

But that would be just too logical for everyone and many systems in many countries have already adopted their preferred format. For me in the UK we have the date in reverse, eg. 10-Jan-2006 (smallest unit -> largest), whereas Americans have an almost random order with Jan-10-2006 (middle unit -> smallest -> largest). I don’t know of any other system of measurement that is affected like this, we don’t have measurements like ’4m 8mm 12cm’ or ’4lbs 8st’, so why measure time differently? So, many countries like the UK need to take extra care when dealing with dates, unlike the US which sets the standard in many languages/development tools like .NET. With the difference between the UK and US date formats it can be rather ambiguous when working with the first 12 days of any month. For example, 10/08/2006 in the UK would be regarded as the 10th of August, whereas in the US this would be the 8th of October.

Now, .NET does have it’s ways of handling these issues, but of course there’s always more than one way to skin a cat as they say.

When converting a DateTime value to say a string the conversion is relatively simple, there are mechanisms for producing the date in whatever format you choose. One way is to use the old VBScript Format function eg.

Dim str As String = Format(Now, "dd-MM-yy")

Which gives the current date in the Format defined by the string “dd-MM-yy” as a string. But in .NET we want to avoid using the old VBScript methods and instead use the .NET framework. For this .NET provides the ability to format various objects for conversion to strings in the very method that does the conversion, i.e. the ‘ToString’ method:

Dim str As String = Now.ToString("dd-MM-yy")

Well that’s the easy side covered as a String object is both fairly simple in its definition and flexible in it’s data, the Date object on the other hand is a little more complex in structure and far more constrained in its data. The process of converting a date contained in a String object for transfer into a Date/DateTime object can be a little more challenging.

I’ve seen many people suggest using the following:

Dim myDateTime As DateTime = Convert.ToDateTime("01/02/2006")

Apparently, the interpretation of a date string, e.g. ’01/02/2006′, is rather dependant on the locale settings of the machine on which it is running. But I haven’t been able to replicate this at all. Regardless of whether my regional setting is set to US or English and even though it states very clearly in the regional settings that the US format is ‘Month/Day/Year’, the string above is still interpreted as ‘Day/Month/Year’. So, it appears that I might as well use the Convert.ToDateTime method of reading date strings and stop worrying, but I won’t….

For starters the Convert.ToDateTime method invokes the DateTime.Parse method according to MSDN, so the following seems more efficient:

Dim myDateTime As DateTime = DateTime.Parse("01/02/2006")

Which again gives me the same results regardless of regional setting. I’d rather not rely on this very loose method of string to date conversion, especially when I have no idea why the regional setting isn’t making a difference. The methods so far are very open and return a date of ’01/02/2006′ interpreted as the 1st of February, 2006 for all of these strings: ’01/02/2006′, ’01/02/06′, ’01-02-2006′, ’01-02-06′, ’01.02.2006′, ’01.02.06′, ‘feb 01 06′, 01 feb 06′, ’2006 feb 01′, ‘february 1 2006′, ’1.2.6′, etc, etc. I don’t know about you, but I’d say that was pretty loose.

There is a more strict alternative, which is the DateTime.ParseExact method and this will allow a particular expected date and time format to be specified. The ParseExact method I’ll be looking at takes 3 parameters, the date string to be converted, a format string and something called an IFormatProvider which contains information about a particular culture to be used. For the initial example I shall not provide any information about the culture and simply pass ‘Nothing’ as the third parameter. So, if we store our date string to be converted in a string variable called ‘myString’ for example:

Dim myDateTime as DateTime = DateTime.ParseExact(myString, "dd/MM/yyyy", Nothing)

This will throw a ‘FormatException’ exception for any value in myString that does not exactly match the ‘dd/MM/yyyy’ format string. So anything like ’01-02-2006′, ’01/02/06′ or ’1/2/2006′ will all result in generating an exception. Although, for the last example it would be valid if you set the format string to ‘d/M/yyyy’ since a single ‘d’ or ‘M’ allows 1 or 2 digit values, whereas ‘dd’ and ‘MM’ allows only 2 digits so you must prefix single digit values with zeros.

You can also use format characters to represent whole format strings, such as ‘d’ which indicates a ShortDatePattern, ‘D’ is for a LongDatePattern, ‘G’ indicates a General format with a short date and a long time, etc. The whole list of these are available from MSDN along with the format pattern information for creating your own format strings like the ‘dd/MM/yyyy’ I used above.

This isn’t so bad if you are only ever going to receive the date string in one particular format, but you might want to allow some variations on the date format. We’re not trying to limit the format of the date strings we can successfully convert to DateTime objects, all we’re really after is being safe in the knowledge that we are interpreting the date strings correctly and consistently. Using the UK format I want to be sure that whenever the day and month values are represented in numerical format, that the first value is the day and the second is the month for example. So in order to specify several format strings you can pass a string array rather than just one string, again with our date string stored in myString:

Dim myFormatStrings() as String = {"d", "D"}
Dim myDateTime as DateTime = DateTime.ParseExact(myString, myFormatStrings, Nothing)

Which will convert date strings in the Short and Long formats. Also…

Dim myFormatStrings() as String = {"d/M/yyyy", "d-M-yyyy"}
Dim myDateTime as DateTime = DateTime.ParseExact(myString, myFormatStrings, Nothing)

Will allow dates with 1 or 2 day and month numbers and a 4 digit year, with either ‘/’ or ‘-’ date separators.

Finally, I should probably say a few words about the third parameter for ParseExact, IFormatProvider, since it’s not a good idea to pass Nothing as I have done so far. This parameter can be specified in a few ways but I’ll only show one here, there’s a fair few examples around the net on this if you need more info. It is possible to select the format provider based on the current culture setting for the machine, but as I mentioned before, I’d rather be a little more specific about what I require. So this example will explicitly set the format provider to “en-GB”, known as English – Great Britain. In a nutshell I create an IFormatProvider object by supplying my specific culture to the CultureInfo method of System.Globalization. So using myString and myFormatString from examples above:

Dim myFormatProvider as IFormatProvider = New System.Globalization.CultureInfo("en-GB")
Dim myDateTime As DateTime = DateTime.ParseExact(myString,myFormatString,myFormatProvider)

And that’s that, besides since I got married a couple of months ago you would think I wouldn’t need to worry about dates anymore…