Почему эта конкретная строка формата TimeSpan перестала работать в .NET 4?

Рассмотрим этот код (предварительно заполненный примером):

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}", ts ));

Это образец кода, с которым я работал, по крайней мере, начиная с .NET 1.1.

Он отлично работал в версиях с 1.1 по 3.5 со следующим выводом (для этих фиктивных входных данных):

30.00:00:28.3580246

Но теперь я вижу, что он умирает в .NET 4 с сообщением об ошибке:

Input string was not in a correct format.

Так что это как если бы .NET 4 вдруг решил, что ему не нравится этот формат для разницы во времени. Изменение строки, скажем,

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

имеет тот же эффект.

Теперь я заметил, что если я просто делаю .ToString() по умолчанию, я получаю тот же результат. Я полагаю, что мыслительный процесс заключался в том, что это был страховой полис от изменения формата по умолчанию в будущей версии. Но теперь это не похоже даже на вариант.

Кто-нибудь знает, почему это изменилось, и если я делаю что-то не так, или есть ли лучший способ сделать то, что я пытаюсь сделать?


person Tom Kidd    schedule 30.07.2010    source источник


Ответы (5)


Существует переключатель конфигурации для восстановления старого поведения TimeSpan.

person Mitch Wheat    schedule 30.07.2010
comment
Так что в основном эта строка формата ничего не делала все это время. Выдающийся. Спасибо. - person Tom Kidd; 30.07.2010
comment
@Шнаппл Точно. В .NET 3.5 и более ранних версиях структура TimeSpan не была IFormattable. Когда string.Format и связанные с ним методы видят что-то вроде {0:something}, а предоставленный аргумент не IFormattable, им некуда поместить эту строку формата, и они просто отбрасывают ее. Это то, что происходило в вашем коде до появления .NET 4.0. - person Jeppe Stig Nielsen; 07.07.2013

Альтернативой переключателю конфигурации является изменение формата, совместимое с предыдущими версиями.

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

Это решение подробно здесь< /а>.

person wilk    schedule 30.08.2010
comment
Это исправило это для меня :) - person Fiona - myaccessible.website; 10.09.2013

На самом деле строка составного формата, которую вы использовали в своем коде, не имела никакого эффекта, поскольку TimeSpan не поддерживает строки пользовательского формата (.NET ‹ 4.0 ).

то есть ваш TimeSpan всегда будет отформатирован как 30.00:00:28.3580246 независимо от строки формата.

Из MSDN:

В предыдущих версиях .NET Framework структура TimeSpan не реализовывала IFormattable и не поддерживала строки формата.

Однако многие разработчики ошибочно предположили, что TimeSpan поддерживает набор строк формата, и использовали их в составных операциях форматирования с помощью таких методов, как String.Format. Обычно, если тип реализует IFormattable и поддерживает строки формата, вызовы методов форматирования с неподдерживаемыми строками формата обычно вызывают исключение FormatException. Однако, поскольку TimeSpan не реализовал IFormattable, среда выполнения проигнорировала строку формата и вместо этого вызвала метод TimeSpan.ToString(). Это означает, что, хотя строки формата не влияли на операцию форматирования, их присутствие не приводило к FormatException.

person Saeb Amini    schedule 25.08.2014

Как указано Митчем Уитом и Саебом Амини в их ответы, TimeSpan не реализует IFormattable до .NET 4.0. Следовательно, строки формата не влияют на вывод TimeSpan.ToString(), поскольку они игнорируются.

Однако, поскольку TimeSpan не реализовал IFormattable, среда выполнения проигнорировала строку формата и вместо этого вызвала метод TimeSpan.ToString. Это означает, что, хотя строки формата не повлияли на операцию форматирования, их присутствие не приводило к FormatException.

Источник

Тем не менее, если вы хотите отформатировать значение TimeSpan во всех версиях .NET framework, гораздо лучше преобразовать значение 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
person Alex Essilfie    schedule 02.01.2015

Я вставил ваш фрагмент кода, и это похоже на проблему с культурой:

с .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);
person Florian    schedule 30.07.2010
comment
Я думаю, что вы что-то понимаете в культуре, но меня бесят не строки DateTime, а строка формата TimeSpan. Даже если я укажу культуру в TimeSpan ToString и обоих методах DateTime.Parse, я все равно получаю то же самое. - person Tom Kidd; 30.07.2010