New Format on the Block [Anthony Moore]

One thing that has not changed much in Whidbey is the set of format strings used by base data types for parsing and formatting. However, there is one new format element supported by the DateTime class that can be very useful if you use the ParseExact method to parse XML.

 

There is a new format element “F”, which is very much like the existing lower case format element “f”, which represents a digit of a fraction of a second. For example the time string “03:24:33.020” might be parsed or formatted with the format string “HH:mm:ss.fff”. One problem with “f” is that is a bit inflexible. When used with DateTime.ToString, it will always emit exactly the specified number of fraction digits, and when used with DateTime.ParseExact, it will only successfully match exactly that number of digits. The “F” format with DateTime.ToString is the same except that it does not output trailing zeros. However, with DateTime.ParseExact it will accept any string with up to the specified number of fraction digits, rather than requiring a exact number.

 

The benefit of this is clear if you look at some code using DateTime.ParseExact. Typical XML date parsing code might look like this:

 

public DateTime XmlStringToDateTime(String input) {

    String[] allFormats = new string[] {

                    "yyyy-MM-ddTHH:mm:ss",

                    "yyyy-MM-ddTHH:mm:ss.f",

                    "yyyy-MM-ddTHH:mm:ss.ff",

                    "yyyy-MM-ddTHH:mm:ss.fff",

                    "yyyy-MM-ddTHH:mm:ss.ffff",

                 "yyyy-MM-ddTHH:mm:ss.fffff",

                    "yyyy-MM-ddTHH:mm:ss.ffffff",

                    "yyyy-MM-ddTHH:mm:ss.fffffff",

                    "yyyy-MM-ddTHH:mm:ssZ",

                    "yyyy-MM-ddTHH:mm:ss.fZ",

                    "yyyy-MM-ddTHH:mm:ss.ffZ",

                    "yyyy-MM-ddTHH:mm:ss.fffZ",

                    "yyyy-MM-ddTHH:mm:ss.ffffZ",

                    "yyyy-MM-ddTHH:mm:ss.fffffZ",

                    "yyyy-MM-ddTHH:mm:ss.ffffffZ",

                    "yyyy-MM-ddTHH:mm:ss.fffffffZ",

                    "yyyy-MM-ddTHH:mm:sszzzzzz",

                    "yyyy-MM-ddTHH:mm:ss.fzzzzzz",

                    "yyyy-MM-ddTHH:mm:ss.ffzzzzzz",

                    "yyyy-MM-ddTHH:mm:ss.fffzzzzzz",

                    "yyyy-MM-ddTHH:mm:ss.ffffzzzzzz",

                    "yyyy-MM-ddTHH:mm:ss.fffffzzzzzz",

                    "yyyy-MM-ddTHH:mm:ss.ffffffzzzzzz",

                    "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz",

                    "HH:mm:ss",

                    "HH:mm:ss.f",

                    "HH:mm:ss.ff",

                    "HH:mm:ss.fff",

                    "HH:mm:ss.ffff",

                    "HH:mm:ss.fffff",

                    "HH:mm:ss.ffffff",

                    "HH:mm:ss.fffffff",

                    "HH:mm:ssZ",

                    "HH:mm:ss.fZ",

                    "HH:mm:ss.ffZ",

                    "HH:mm:ss.fffZ",

                    "HH:mm:ss.ffffZ",

                    "HH:mm:ss.fffffZ",

                    "HH:mm:ss.ffffffZ",

                   "HH:mm:ss.fffffffZ",

                    "HH:mm:sszzzzzz",

                    "HH:mm:ss.fzzzzzz",

                    "HH:mm:ss.ffzzzzzz",

                    "HH:mm:ss.fffzzzzzz",

                    "HH:mm:ss.ffffzzzzzz",

                    "HH:mm:ss.fffffzzzzzz",

                    "HH:mm:ss.ffffffzzzzzz",

                    "HH:mm:ss.fffffffzzzzzz",

         };

   return DateTime.ParseExact(input,

                              allFormats,

                              CultureInfo.InvariantCulture

                              DateTimeStyles.None);

}

Apart from looking horrible, this is very very slow, because DateTime.ParseExact just tries to parse each one of these in turn. In the worst case this is like calling ParseExact with a single string 42 times!

Using the “F” format, the code above can be simplified to this:

public DateTime XmlStringToDateTime(String input) {

    String[] allFormats = new string[] {

        String[] condensedDateTimeFormats = new string[] {

                    "yyyy-MM-ddTHH:mm:ss.FFFFFFF",

                    "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ",

                    "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzzzzz",

                    "HH:mm:ss.FFFFFFF",

                    "HH:mm:ss.FFFFFFFZ",

                    "HH:mm:ss.FFFFFFFzzzzzz",

         };

   return DateTime.ParseExact(input,

                              allFormats,

                              CultureInfo.InvariantCulture

                              DateTimeStyles.None);

}

The “F” format will be available in Whidbey Beta 2. Of course it would be nice to improve even on this and just provide a single string like “(yyyy-MM-ddT)+HH:mm:ss(Z|zzz)+”, but we would have to look at that in a future release.