Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interpreting dates: Console.Writeline vs. string.Format

Given the following C# code:

var dt = DateTime.Now;
Console.WriteLine("{0:MM/dd/yy} ... {1}", dt, string.Format("{0:MM/dd/yy}", dt));

... when the short date (under Windows 7, Control Panel -> Region and Language -> Additonal Settings -> Date) is set to the USA standard of "M/d/yyyy," I get this:

06/17/14 ... 06/17/14

However, when I change the short date to "ddd dd MMM yyyy," I get this:

06/17/14 ... 06 17 14

I was under the impression that Console.WriteLine and string.Format always string formatted DateTime values identically. What is the explanation for this discrepancy?

EDIT: Looks like this happens only in standard unit test output (Visual Studio), which is where I originally saw the problem. When the code executes in a console app, the output is 06 17 14 ... 06 17 14.

like image 254
MiloDC Avatar asked Jun 18 '14 05:06

MiloDC


1 Answers

This situation arises because when MSTest redirects console output to the test window, it passes CultureInfo.InvariantCulture to the TextWriter associated with the console.

You can verify this with the following:

var threadCulture = Thread.CurrentThread.CurrentCulture;
var consoleCulture = Console.Out.FormatProvider;

Console.WriteLine(threadCulture.Equals(CultureInfo.InvariantCulture));
Console.WriteLine(consoleCulture.Equals(CultureInfo.InvariantCulture));

Unless you change it, the thread's current culture is usually something like en-US, or whatever your computer is set to. So the first item will usually be false.

But the second item varies depending on where it's run from. As a console application, the console output culture should default to the current thread culture - so it will be false. In XUnit or NUnit tests, the result is also false. But in MSTest, the result is true.

If you dig through the .NET Framework Reference Source, you'll see that

  • Console.WriteLine calls Out.WriteLine

  • Out is a TextWriter, and TextWriter.WriteLine uses its assigned FormatProvider

  • The FormatProvider is either null to use the current thread, or is assigned by constructor parameter.

I don't think the sources for the MSTest test runner are publicly available, but one can conclude that they must somewhere do something like:

Console.Out = new SomeWriter(CultureInfo.InvariantCulture);

Where SomeWriter creates the test output and inherits from TextWriter.

On the other hand, String.Format will always use the thread's current culture, unless you specifically provide a different culture.

One way to work around this would be to explicitly set the thread's current culture to the invariant culture.

Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
like image 184
Matt Johnson-Pint Avatar answered Sep 28 '22 02:09

Matt Johnson-Pint