解读日期:Console.Writeline与string.Format

6

给定以下 C# 代码:

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

当短日期(在Windows 7下,可以进入“控制面板-区域和语言-附加设置-日期”)设置为美国的标准格式“M/d/yyyy”时,我会得到以下结果:
06/17/14 ... 06/17/14

然而,当我将短日期更改为"ddd dd MMM yyyy"时,会得到以下结果:
06/17/14 ... 06 17 14

我曾以为Console.WriteLinestring.Format总是以相同的方式格式化DateTime值。这种差异的解释是什么? 编辑:看起来这只会发生在标准单元测试输出(Visual Studio)中,这也是我最初看到问题的地方。当代码在控制台应用程序中执行时,输出为06 17 14 ... 06 17 14

当您明确设置格式字符串时,您的系统设置不应该有任何影响。我认为这里发生了其他事情。 - Enigmativity
实际上这是有关系的,因为 "/" 不是字面字符,而是分隔符,实际输出取决于文化环境,例如在德国会是 "."。但这并不能解释为什么在使用相同显式格式的 Console.WriteLineString.Format 时输出不同。 - Dirk
@Enigmativity:嗯,显然修改短日期相当于改变.NET所涉及的文化。我只是想知道为什么这两个方法调用的行为不同。 - MiloDC
@Dirk:没错。看起来很奇怪。 - MiloDC
我在使用Win 7操作系统,从.net framework 2.0到4.5.1进行测试时,发现Console.WriteLine和string.Format输出的结果相同,都是06 17 14 ... 06 17 14 - LostInComputer
阅读了LostInComputer得到不同结果的信息后,我创建了一个新项目并再次尝试。我得到了和他/她一样的结果:06 17 14 ... 06 17 14。我的原始项目输出是从一个单元测试中写入的(标准的,使用Microsoft.VisualStudio.TestTools.UnitTesting),因此我创建了一个新的单元测试项目,结果从单元测试读取为06/17/14 ... 06 17 14。请问有人可以尝试一下并让我知道你是否得到了不同的输出? - MiloDC
2个回答

3
这种情况的出现是因为当MSTest将控制台输出重定向到测试窗口时,它会将 CultureInfo.InvariantCulture 传递给与控制台相关联的 TextWriter
您可以通过以下方式进行验证:
var threadCulture = Thread.CurrentThread.CurrentCulture;
var consoleCulture = Console.Out.FormatProvider;

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

除非您更改它,否则线程的当前区域性通常类似于en-US或您计算机设置的任何内容。因此,第一项通常为false。
但第二项取决于其运行的位置。作为控制台应用程序,控制台输出区域设置应默认为当前线程区域设置-因此它将为false。在XUnit或NUnit测试中,结果也是false。但在MSTest中,结果为true。
如果您深入研究.NET Framework Reference Source,您会发现

我认为 MSTest 测试运行程序的源代码不是公开的,但可以得出它们一定会做类似以下的事情:

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

SomeWriter 创建测试输出并继承自 TextWriter

另一方面,String.Format 将始终使用线程的当前区域设置,除非您专门提供不同的区域设置。

解决这个问题的一种方法是将线程的当前区域设置显式地设置为不变的区域设置。

Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

谢谢解释,马特! - MiloDC
1
感谢您提出这个好问题! - Matt Johnson-Pint

1
这是由于Format方法解释/符号的方式不同导致的。
来自MSDN
如果自定义格式字符串包括“/”格式说明符,则DateTime.ToString方法将在结果字符串中显示DateSeparator的值,而不是“/”。
DateSeparator属性定义了在格式化操作中替换日期分隔符(“/”自定义日期和时间格式说明符)的字符串。它还定义了解析操作中的日期分隔符字符串。
当您更改格式时,默认符号会更改为空格字符。
如果您需要显示/字符,则可以通过使用\来转义它。因此,将格式字符串更改为{0:MM\/dd\/yy}将始终显示/

我已经知道这个了。问题不在于斜杠被更改为空格,而在于两个方法调用产生了不同的结果。正如我所指出的那样,这似乎只发生在测试输出中。 - MiloDC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接