2

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?

Paul Hollingsworth
  • 13,124
  • 12
  • 51
  • 68
  • You're calling `DateTime.MaxValue.ToString` without a culture - are you sure this string is being formatted correctly? (I don't know how fo-FO formats its date strings...) – Tim Robinson Jul 28 '10 at 12:43
  • I've got exception in both cases. What version framework you used? – Denis Palnitsky Jul 28 '10 at 12:45
  • 1
    @Adam What works is: invariant culture can parse a string produced by en-US. However, invariant culture can't parse a string produced by fo-FO. – Tim Robinson Jul 28 '10 at 12:46
  • Actually, the strings aren't the same. Culture is playing a part when the `ToString` is called even if you manually specify the format. – Adam Houldsworth Jul 28 '10 at 12:52

5 Answers5

9

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
  • 62,551
  • 17
  • 151
  • 186
1

If you do not want to respect any timezones in the parsing you could use

var d = DateTime.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);

or

var d = DateTime.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
1

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.
  • 7,313
  • 30
  • 39
0

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
  • 3,930
  • 1
  • 25
  • 28
  • 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 Jul 28 '10 at 13:28
0

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
  • 17,233
  • 9
  • 65
  • 88