Interpreting dates: Console.Writeline vs. string.Format
Asked Answered
R

2

6

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.

Roughrider answered 18/6, 2014 at 5:25 Comment(6)
It shouldn't matter what your system settings are when you explicitly set the format string. I think something else is going on here.Hypothetical
Actually it can matter since the "/" are not literal characters but seperators and the actual output depends on the culture, e.g. in Germany it would be a ".". But that doesn't explain why the output is different when using the same explicit format in Console.WriteLine and String.Format.Tegan
@Enigmativity: Well, altering the short date apparently amounts to changing the culture, as far as .NET is concerned. I just wonder why the two method calls don't behave the same.Roughrider
@Dirk: Right. Seems odd.Roughrider
I get the same output for both Console.WriteLine and string.Format which is 06 17 14 ... 06 17 14 . I'm using Win 7 and did the test from .net framework 2.0 to 4.5.1Titanite
After reading that LostInComputer got a different result, I created a new project and tried it again. I got the same result as he/she: 06 17 14 ... 06 17 14. The output from my original project was written from a unit test, though (standard, using Microsoft.VisualStudio.TestTools.UnitTesting), so I created a new unit test project, and voila, the output from the unit test read 06/17/14 ... 06 17 14. Can someone please try this and let me know whether you get different output?Roughrider
S
3

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

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;
Sackville answered 18/6, 2014 at 22:43 Comment(0)
A
1

This is due to how the Format method interpreters the / symbol.

From MSDN

If a custom format string includes the "/" format specifier, the DateTime.ToString method displays the value of DateSeparator in place of the "/" in the result string.

The DateSeparator property defines the string that replaces the date separator ("/" custom date and time format specifier) in a result string in a formatting operation. It also defines the date separator string in a parsing operation.

When you are changing the format, the default symbol is changed to space character.

If you need to display the / character, it can be escaped by using \. Thus changing the format string to {0:MM\/dd\/yy} will always display /.

Ard answered 18/6, 2014 at 12:37 Comment(1)
I already know this. The issue not that the slash is changed to whitespace, the issue is that the two method calls yield different results. As I've noted, this appears to happen only in test output.Roughrider

© 2022 - 2024 — McMap. All rights reserved.