tags:

views:

94

answers:

4

Consider the following code:

class Program
{
    static void Main(string[] args)
    {
        try
        {
            System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("fo-FO");
            var s = DateTime.MaxValue.ToString("yyyy-MM-ddTHH:mm:ssZ");
            var d = DateTime.Parse(s, CultureInfo.InvariantCulture);
            Console.WriteLine("Was able to parse with fo-FO");
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: {0}", e);
        }

        try
        {
            System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
            var s = DateTime.MaxValue.ToString("yyyy-MM-ddTHH:mm:ssZ");
            var d = DateTime.Parse(s, CultureInfo.InvariantCulture);
            Console.WriteLine("Was able to parse with en-US");
        }
        catch (Exception e)
        {
            Console.WriteLine("Exception: {0}", e);
        }
    }
}

The output is:

Exception: System.FormatException: String was not recognized as a valid DateTime.
   at System.DateTimeParse.Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
   at System.DateTime.Parse(String s, IFormatProvider provider)
   at DateTimeTest2.Program.Main(String[] args) in C:\Projects\DateTimeTest2\DateTimeTest2\Program.cs:line 17
Was able to parse with en-US

This code fragment proves that DateTime.Parse uses Thread.CurrentThread.CurrentCulture regardless of the fact that the "InvariantCulture" is being passed in. I find this so unintuitive that I consider it a "bug".

Why do we have to pass in a CultureInfo if it is in fact ignored by DateTime.Parse in any case? Is there a way of calling DateTime.Parse in a way that is independent of the CurrentCulture?

+9  A: 

This code fragment proves that DateTime.Parse uses Thread.CurrentThread.CurrentCulture regardless of the fact that the "InvariantCulture" is being passed in

I'm not sure how this example proves that. The strings passed to DateTime.Parse are different, so it's not completely surprising that different results ensue.

The first string has the time formatted as 23.59.59, which (apparently) InvariantCulture cannot parse; the second string has the time formatted as 23:59:59, which InvariantCulture can parse. What's the problem?

edit to add, since apparently it makes a difference, I am running with .NET 2.0 and the strings produced by fo-FO and en-US are respectively

9999-12-31T23.59.59Z

and

9999-12-31T23:59:59Z
AakashM
+1 good spot, I think initially it was assumed both strings were the same. I didn't notice that until I read your answer.
Adam
A: 

Both parses use InvariantCulture, which is the actually a hard-coded reference to the 'en-US' culture (there may be casses where the InvariantCulture is not 'en-US' but I haven't come accross them).

Replace your use of InvariantCulture with new CultureInfo("en-US") and it will become obvious why the first parse doesn't work.

Dr Herbie
Actually, the two are not the same. See http://stackoverflow.com/questions/2329297/net-are-there-any-differences-between-invariantculture-and-en-us
Daniel Rose
Ah, thank you. That's useful.
Dr Herbie
+1  A: 

from MSDN:

The invariant culture is culture-insensitive. Your application specifies the invariant culture by name using an empty string ("") or by its language identifier. InvariantCulture retrieves an instance of the invariant culture. It is associated with the English language but not with any country/region.

I could not find any reference to using the current thread's culture, as that would be counter-intuitive as you said.

You could (as a workaround) cache the current thread's culture, set it to a known good culture (en-US), perform your parsing, then set the thread's culture back to the old value.

CultureInfo ci = System.Threading.Thread.CurrentThread.CurrentCulture;
System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
var s = DateTime.MaxValue.ToString("yyyy-MM-ddTHH:mm:ssZ");
var d = DateTime.Parse(s, CultureInfo.InvariantCulture);
System.Threading.Thread.CurrentThread.CurrentCulture = ci;

This will guarantee you know what culture is being used to parse the DateTime string and will not affect outside calling code because the culture is never changed from an outside perspective.

Scott M.
A: 

In addition to what AakashM wrote:

I tried running it in .NET 3.5 SP1. In the second case, I get a System.FormatException stating that the value of the DateTime is out of range.

Daniel Rose