8

I have recently upgraded a ASP.Net forms application to .Net 4.5.2, after fixing some relatively trivial namespace issues I was able to build the solution successfully. However at runtime I have been receiving the following error:

An exception of type 'System.FormatException' occurred in mscorlib.dll but was not handled in user code

Which when debugging is thrown by the following line:

string.Format("Init took {0:mm:ss}", (object) DateTime.Now.Subtract(renderStartTime))  

Where renderStartTime = DateTime.Now

I am somewhat puzzled why I am seeing this error since upgrading. Any thoughts?

Matt
  • 825
  • 2
  • 13
  • 25

3 Answers3

6

It is a breaking change.

See: Formatting and Parsing Time Intervals in the .NET Framework 4

In the .NET Framework 3.5 and earlier versions, TimeSpan does not implement IFormattable, nor does it support format strings. Therefore, the “r” format string is ignored, and the parameterless TimeSpan.ToString method is called. In the .NET Framework 4, on the other hand, TimeSpan.ToString(String, IFormatProvider) is called and passed the unsupported format string, which causes the exception.

Just to expand on the answer, your original code in .Net framework 2.0 would not throw an exception but it will not give you the desired output, (minutes:seconds). Since the parameter less constructor would be call for TimeSpan, ignoring the format specified in String.Format. But, with .Net framework 4.0 or hgiher , since TimeSpan implements IFormattable, the format specified mm:ss would be passed to the ToString call. Now this format mm:ss is invalid for TimeSpan, it requires colon to be escaped with back slash like: mm\:ss. That is why you are getting exception.

See: Custom TimeSpan Format Strings

In .Net 3.5 or lower you can use:

TimeSpan elapsed = DateTime.Now - renderStartTime; //or DateTime.Now.Subtract(renderStartTime)
string formatted = string.Format("Init took {0}:{1}", elapsed.Minutes, elapsed.Seconds); //returns minutes and seconds components, 
                                        // If you are looking for Total Minutes and Total Seconds then use TotalMinutes/TotalSeconds

In .Net framework 4.0 or higher you can do:

string.Format("Init took {0:mm\\:ss}", elapsed);
Habib
  • 219,104
  • 29
  • 407
  • 436
3

The problem is the second colon. You can do the following instead

string.Format("Init took {0:mm}:{0:ss}", DateTime.Now.Subtract(renderStartTime));

EDIT

Based on how TimeSpan worked in .Net 3.5 and earlier the original code in .Net 2.0 would actually print out the time in a hh:mm:ss format. Basically the "mm:ss" part of the format was ignored because TimeSpan did not implement IFormattable. So the following in .Net 4.5.2 is really closer to replacing what the original code was doing in .Net 2.0.

string.Format("Init took {0}", DateTime.Now.Subtract(renderStartTime));

But if you want to only show minutes and seconds you can use formatting of either {0:mm}:{0:ss} or {0:mm\\:ss} in .Net 4.0 and higher. Or in .Net 3.5 or earlier you would have to do it like this.

TimeSpan diff = DateTime.Now.Subtract(renderStartTime);
string.Format("Init took {0:00}:{1:00}", diff.Minutes, diff.Seconds);
juharr
  • 31,741
  • 4
  • 58
  • 93
  • This will not return expected value in .Net 2.0. For framework 4.0 or higher even this `string.Format("Init took {0:mm\\:ss}", DateTime.Now.Subtract(renderStartTime));` is enough, But this would not work in .Net 3.5 and below :) – Habib Dec 02 '14 at 16:55
  • @Habib true and I the original code in 2.0 was not returning just minutes and seconds. – juharr Dec 02 '14 at 17:02
3
 Console.WriteLine(string.Format("Init took {0:mm\\:ss}", DateTime.Now.Subtract(renderStartTime)));

Here you need the code to look like this.You can do it like this if you want

 Console.WriteLine(string.Format(@"Init took {0:mm\:ss}", DateTime.Now.Subtract(renderStartTime)));

You can read this microsoft documentation for more help:

The custom TimeSpan format specifiers do not include placeholder separator symbols, such as the symbols that separate days from hours, hours from minutes, or seconds from fractional seconds. Instead, these symbols must be included in the custom format string as string literals. For example, "dd.hh:mm" defines a period (.) as the separator between days and hours, and a colon (:) as the separator between hours and minutes. Custom TimeSpan format specifiers also do not include a sign symbol that enables you to differentiate between negative and positive time intervals. To include a sign symbol, you have to construct a format string by using conditional logic. The Other Characters section includes an example.

mybirthname
  • 17,949
  • 3
  • 31
  • 55