tags:

views:

112

answers:

3

While struggling with DateTime.ParseExact formatting issues, I decided to feed ParseExact the out put from DateTime.ToString(), like this:

DateTime date2 = new DateTime(1962, 1, 27);
string[] expectedFormats = { "G", "g", "f", "F", "D", "d", "M/d/yyy", "MM/dd/yyy", "MM-dd-yyy", "MMM dd, yyy", "MMM dd yyy", "MMMM dd, yyy", "MMMM dd yyy" };
bool parsed = false;

foreach (string fmt in expectedFormats)
{
    try
    {
        DateTime dtDateTime = DateTime.ParseExact(date2.ToString(fmt), fmt, new CultureInfo("en-US"));
        parsed = true;
    }
    catch (Exception)
    {
        parsed = false;
    }

    Console.WriteLine("[{0}] {1}", parsed,date2.ToString(fmt));
}

This is the output:

[True] 1/27/1962 12:00:00 AM
[True] 1/27/1962 12:00 AM
[True] Saturday, January 27, 1962 12:00 AM
[True] Saturday, January 27, 1962 12:00:00 AM
[True] Saturday, January 27, 1962
[True] 1/27/1962
[False] 1/27/1962
[False] 01/27/1962
[False] 01-27-1962
[False] Jan 27, 1962
[False] Jan 27 1962
[False] January 27, 1962
[False] January 27 1962

What do I have to do so that ParseExact will parse the custom format strings? Am I wrong to expect DateTime to be able to ingest it's own output based on the same format string?

+4  A: 

This clearly demonstrates that DateTime.ParseExact is not round-trip safe with Datetime.ToString. I am not sure this is much of an answer, but the problem is definitely related to the 3 digit year format yyy. Since 1962 cannot be represented in 3 digits ToString is forced to use 4 digits. Apparently ParseExact is not smart enough to reverse that logic and instead is looking for exactly 3 digits. The workaround is to use yyyy instead of yyy. I would submit this as a bug to the Microsoft Connect website and see what comes of it.

Brian Gideon
You are right. yyyy fixes the problem.
Martin Ingvar Kofoed Jensen
Indeed it does! Thanks!
Greg Miskin
A: 

I'm suprised seeing this, but the documentation at msdn says:

You can specify one of the standard date and time format specifiers or a limited combination of the custom date and time format specifier

http://msdn.microsoft.com/en-us/library/2h3syy57.aspx

Update

You can use the workaround mentioned in the previous answer.

Martin Ingvar Kofoed Jensen
A: 

I took your code, and changing "yyy" to "yyyy" is enough to return "TRUE" for them all (having first reproduced the "FALSE"s before I made any changes).

The documentation at MSDN is unclear, but does emphasize the need for specifying the full width of every component (e.g. yyyy rather than yyy) without the invariant culture:

http://msdn.microsoft.com/en-us/library/w2sa9yss.aspx

If format is a custom format pattern that does not include date or time separators (such as "yyyyMMdd HHmm"), use the invariant culture for the provider parameter and the widest form of each custom format specifier. For example, if you want to specify hours in the format pattern, specify the wider form, "HH", instead of the narrower form, "H".

Tom Carver
Spaces, dashes, and slashes are date/time separators.
R. Bemrose
I saw that too. But Greg's example code does use separator characters so this clause seems to not apply. It is still good information to point out though.
Brian Gideon
I agree with you guys that the wording on MSDN suggests that date/time separators are the crucial factor, but running the code myself using "yyyy" solves the problem.
Tom Carver