Почему эта конкретная строка формата TimeSpan перестала работать в .NET 4? - PullRequest
5 голосов
/ 30 июля 2010

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

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(), я получу тот же результат.Я считаю, что мыслительный процесс заключался в том, что это был страховой полис от изменения формата по умолчанию в будущей версии.Но теперь это не похоже на то, что это даже вариант.

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

Ответы [ 5 ]

6 голосов
/ 30 июля 2010

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

3 голосов
/ 30 августа 2010

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

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

Это решение подробно здесь .

1 голос
/ 02 января 2015

Как указано Mitch Wheat и Saeb Amini в их ответы , 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
1 голос
/ 25 августа 2014

Фактически, строка составного формата, которую вы использовали в своем коде , вообще не имела никакого эффекта , потому что TimeSpan не поддерживает строки пользовательского формата (. NET <4.0). </p>

, т.е. Ваш временной интервал всегда был бы отформатирован как 30.00:00:28.3580246 независимо от строки форматирования.

Из MSDN:

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

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

0 голосов
/ 30 июля 2010

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

в .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);
...