Nice Clean Example

Summary of .NET format specifier

A discussion of the .NET format specifier and how its used. The relationship between the components and a cheat card of the format specifier details.

.NET formattting, or why I miss sprintf

In the C programming language the sprintf function was one that let you format values into strings. I can still type it out from memory.

sprintf(buffer,"Result is %04.4d",ival);

Assuming that ival was an integer variable this would format the value of ival into the char array called buffer. The leading '0' means that the value is to be zero filled on the left. '4.4' means that there the minimum length of the result is 4 and the maximum is 4. 'd' means that this is a numeric value. The rest of the string, the text before the '%', would pass through as is.

If ival had the value 37 the buffer would have the value "Result is 0037".

Fast forward to the present, and welcome to the .NET formatting capability. Like a lot of the platform it is very full featured, and like a lot of the platform its very complex. Only by setting aside several hours to write this article and create these graphics have I begun to internalize it, and of course I'll lose that knowledge if I don't use it.

If you've used .NET for very long, whether its VB or C#, you've come across the very cool method that all variables and objects have, "ToString()", to let you quickly print out a formatted version of the value. If you have dug deeper you have found that, for common variable types, ToString() can take a string argument to format the value, somethign like this:

int ival = 37;
string s = ival.ToString("D4"); // produces "0037"

If you have explored further you probably have found the built-in String class has a method called "Format", which takes a string that lets you format one or more variables, something like this:

DateTime now = System.DateTime.Now; // Assume that today is Thursday

string s = String.Format("Hey {0}, today is {1:dddd}", "john",now);

// result is "Hey john, today is Thursday"

If you're like me it has taken some time to figure out when you could specify the form with the {} in it and when you could only specify a single value.

String.Format("D4",ival);            // Not Correct!
ival.ToString("Your value is {0}");  // Not Correct!

Another mystery is why the same apparant format specifier does different things depending on the type of the variable, and how the platform "knows" how to apply certain formatting.

int ival = 37;
DateTime now = System.DateTime.Now;
string s = ival.ToString("D");	// produces "37"
string t = now.ToString("D");	// produces Thursday, 26 July 2007

The answer to the just asked question (why the same format specifier produces different results) is that they are not, in fact, the same format specifier. In addition, .NET knows the types of variables so it knows how to make decisions based on that. In this example .NET knows that the variable "ival" is an integer and so it brings in the format specifiers that is specific to numbers. .NET also knows that the variable "now" is of type datetime, so it brings in the datetime format specifiers. The fact that there is a "D" for numbers and a "D" for datetimes is coincidence.

Its all in the docs, of course, but like all meaty Microsoft docs you get all of the information, which means much more than you actually need to learn how to use it. This is inevitable and appropriate, of course, I'm a huge fan of MSDN, but I know that their audience is everyone, not just people trying to learn how to use somethign. They have to target people writing controls, or doing advanced work.

And so, here is a graphic that shows the relationship between the long form of the format string and the short form, and where the format specifier ("D4" or "dddd") fits in. Following the graphic there is a table that summarizes the format specifiers for each category. I've also created an online utility that can help with development of datetime custom format specifiers. Its located on this website at this link.

Format Specifiers
Standard Numeric Form is Ann, where A is one of C D E F G N P R X and nn is precision
Custom Numeric Assembled from of 0 # . , % E0 E+0 E-0 \ ; 'literal'
Standard DateTime One of d D f F g G M o R s t T u U Y
Custom DateTime
  • Assembled from %c where c is one of d f F g h H K m M s t y z
  • Can repeat specifiers for more precision (except K)
  • Can also contain / 'literal' \ :
  • Enumeration One of g f d x

    From this shortcut it should take you less time to get where you need to go. As time goes on I will continue to develop this topic with more help and discussion.

    1 responses