A small foray into the world of .NET DateTime format specifiers, culture, and the like.
When converting a date to a string, let’s say to ISO 8601 using the user’s current culture, you have several ways of specifying the format of the resulting string:
1 | string formattedDate = date.ToString( "s" , CultureInfo .CurrentCulture); |
and
1 2 | string formattedDate = date.ToString(DateTimeFormatInfo.CurrentInfo.SortableDateTimePattern, CultureInfo .CurrentCulture); |
We can obviously not include the CultureInfo.CurrentCulture, as that is what will be used automatically if no culture is provided, however I have a rule where I always provide a format provider if one can be provided.
Difference?
What’s the difference between the “s” specifier and the SortableDateTimePattern property? They’re both strings, so does the SortableDateTimePattern simply resolve to an “s” as well?
Actually, the SortableDateTimePattern property returns a constant of the format itself:
yyyy’ – ‘MM’ – ‘dd’T’HH’:’mm’:’ss
If you format using the specifier instead, the framework will essentially go through a large switch statement that basically pairs up the individual one-character specifier directly to a property such as SortableDateTimePattern.
Do all date format properties simply return a constant format string like SortableDateTimePattern? Certainly not, as many of the formats of course depend on the culture and calender settings. That’s the whole reason we have formats in the first place, as a short date isn’t always mm/dd/yyyy, for example.
So which is which? The following are two lists, one of formats that are constant, and one of formats that depend on the calendar settings.
Constant Format Properties
- RFC1123Pattern
- SortableDateTimePattern
- UniversalSortableDateTimePattern
Format Properties Affected by Calendar Settings
- FullDateTimePattern
- LongDatePattern
- ShortDatePattern
- YearMonthPattern
- ShortTimePattern
- LongTimePattern
Format Specifiers vs. Format Properties
So what’s the best thing to use? That really depends. If you want one of the formats listed above, and you have an initialized DateTimeFormatInfo object, then the fastest way to get the format you want is by using one of the format properties.
When do you have an initialized DateTimeFormatInfo object? Well, obviously if you have one declared and initialized locally. Other than that, if you refer to my previous article you essentially have one already initialized for you at any time following the first access of DateTimeFormatInfo.CurrentInfo or CultureInfo.CurrentCulture.DateTimeFormat per thread, assuming a constant culture over time. You already have one initialized for you at any time following the first access of DateTimeFormatInfo.InvariantInfo or CultureInfo.InvariantInfo.DateTimeFormat per Application Domain. There are many other actions that result in the framework accessing one of these as well.
Does this matter much in the long run? Nope. Does it matter at all? The difference, although miniscule, is a difference, so unless your goal in life is to be ignorant (a common goal, even among professionals), there’s no harm in knowing and doing.
So, it’s safe to assume that we always have an instance available (expect for maybe the first attempt), so if the format I’m interested in corresponds to one of the known format properties, I’ll always use the DateTimeFormatInfo property.
If you are using a long format string where you’d like to include the specifier in the string, then feel free to just use one of the specifiers. Although the DateTimeFormatInfo class is designed in a way that would permit the specifiers to change without requiring classes using it to have to recompile, I find it very unlikely that would ever happen, as that would just cause sheer pandemonium.
Additionally, there are many formats that do not have their own format property.
Standard Format Specifiers with no Equivalent Property
- f : Full date and time
- g : General (short date and short time)
- G : General (short date and long time)
- o, O : Round-trip date/time patterns
- U : Full date and time (long date and long time) using universal time
If you wish to use one of these formats, you’re stuck with the specifier. From there, there are many other custom, or non-standard formats that will also require the use of a specifier.
Conclusion
The most important thing is to be consistent. The second more important thing is to use common sense in when to break consistency, so you don’t hang yourself trying to maintain your policy.
That aside, I will always use date time format properties when dealing with the standard formats that map to said properties, and I will always use specifiers when dealing with custom formats.