C# 为什么这个特定的TimeSpan格式字符串在.NET4中停止工作?

C# 为什么这个特定的TimeSpan格式字符串在.NET4中停止工作?,c#,.net,formatting,.net-4.0,timespan,C#,.net,Formatting,.net 4.0,Timespan,考虑以下代码(用示例预先填充): 这是我从.NET1.1开始工作的一段代码的代表 它在1.1到3.5中运行良好,具有以下输出(对于这些模拟输入): 但现在我看到它在.NET 4中消失,并显示错误消息: 输入字符串的格式不正确。 所以,就好像.NET4突然决定不喜欢这种时差格式。把线路改成,比如说 Console.WriteLine(string.Format( "{0}", ts.ToString("d.hh:mm:ss.ff") )); 也有同样的效果 现在我注意到,如果我只执行默认的.To

考虑以下代码(用示例预先填充):

这是我从.NET1.1开始工作的一段代码的代表

它在1.1到3.5中运行良好,具有以下输出(对于这些模拟输入):

但现在我看到它在.NET 4中消失,并显示错误消息:

输入字符串的格式不正确。

所以,就好像.NET4突然决定不喜欢这种时差格式。把线路改成,比如说

Console.WriteLine(string.Format( "{0}", ts.ToString("d.hh:mm:ss.ff") ));
也有同样的效果

现在我注意到,如果我只执行默认的
.ToString()
,我会得到相同的输出。我相信思考的过程是,这是针对未来版本中更改的默认格式的保险单。但现在看来这根本不是一个选择


有人知道为什么会发生这种变化,我是否做了错事,或者是否有一种最佳实践方法来完成我试图完成的任务吗?

我粘贴了您的代码,这似乎是一个文化问题:

对于.NET 2,也会引发FormatException

如果我指定了美国文化(默认情况下,文化为fr fr),则代码可以工作:

DateTime dt1 = DateTime.Parse("7/30/2010 9:33:29.1234567 AM", CultureInfo.GetCultureInfo("en-US"));
您还可以指定一个不变的区域性来忽略该区域性

DateTime dt1 = DateTime.Parse("7/30/2010 9:33:29.1234567 AM", CultureInfo.InvariantCulture);

有一种方法可以恢复的旧行为。

配置开关的另一种选择是与以前版本兼容的格式更改

Console.WriteLine(string.Format( "{0:hh\\:mm\\:ss.ff}", ts )); 

此解决方案非常详细。

事实上,您在代码中使用的复合格式字符串根本没有任何效果,因为
TimeSpan
不支持自定义格式字符串(.NET<4.0)

i、 e.无论格式字符串如何,TimeSpan的格式始终为
30.00:00:28.3580246

从MSDN:

在.NET Framework的早期版本中,TimeSpan结构没有 未实现IFormattable,并且不支持格式字符串

然而,许多开发人员错误地认为TimeSpan确实支持 一组格式字符串,用于复合格式 使用String.Format等方法执行的操作。通常,如果一个类型 实现IFormattable并支持格式化字符串、调用 带有不受支持的格式字符串的格式化方法通常会抛出 格式化异常。但是,因为TimeSpan没有实现 IFormattable,则运行时忽略格式字符串,而调用 TimeSpan.ToString()方法这意味着,虽然 字符串对格式化操作没有影响,但它们的存在对格式化操作没有影响 不会导致格式异常。


正如Mitch Wheat和Saeb Amini在中所指出的,
TimeSpan
没有实现.NET 4.0之前的
IFormattable
。因此,格式字符串对
TimeSpan.ToString()
输出没有影响,因为它们被忽略了

但是,由于TimeSpan没有实现IFormattable,运行时忽略了格式字符串,而是调用了TimeSpan.ToString方法。这意味着,尽管格式字符串对格式化操作没有影响,但它们的存在不会导致FormatException

也就是说,如果希望在.NET framework的所有版本中格式化
TimeSpan
值,最好将
TimeSpan
值转换为
DateTime
,然后格式化结果,如下所示:

DateTime dt1 = DateTime.Parse("7/30/2010 9:33:29.1234567 AM");
DateTime dt2 = DateTime.Parse("6/30/2010 9:33:00.7654321 AM");

TimeSpan ts = dt1 - dt2;

Console.WriteLine(String.Format("{0:d.hh:mm:ss.ff}", new DateTime(ts.Ticks))) 
// prints 30.00:00:28.36

我想你已经了解了文化,但是,让我感到适合的不是日期时间线,而是时间跨度格式字符串。即使我在TimeSpan-ToString和这两个DateTime.Parse方法中指定了区域性,我仍然得到了相同的结果。所以基本上,格式字符串一直没有做任何事情。杰出的。谢谢你,真的。在.NET3.5及更早版本中,
TimeSpan
结构不是
IFormattable
。当
string.Format
和相关方法看到类似
{0:something}
的内容,并且提供的参数不是
IFormattable
时,它们没有地方放置该格式字符串,只需丢弃它。在.NET4.0出现之前,您的代码就是这样的。这为我修复了它:)
Console.WriteLine(string.Format( "{0:hh\\:mm\\:ss.ff}", ts )); 
DateTime dt1 = DateTime.Parse("7/30/2010 9:33:29.1234567 AM");
DateTime dt2 = DateTime.Parse("6/30/2010 9:33:00.7654321 AM");

TimeSpan ts = dt1 - dt2;

Console.WriteLine(String.Format("{0:d.hh:mm:ss.ff}", new DateTime(ts.Ticks))) 
// prints 30.00:00:28.36