I was trying to create an IFormatProvider
implementation that would recognize custom format strings for DateTime objects. Here is my implementation:
public class MyDateFormatProvider : IFormatProvider, ICustomFormatter
{
public object GetFormat(Type formatType)
{
if (formatType == typeof(ICustomFormatter))
{
return this;
}
return null;
}
public string Format(string format, object arg, IFormatProvider formatProvider)
{
if(arg == null) throw new ArgumentNullException("arg");
if (arg.GetType() != typeof(DateTime)) return arg.ToString();
DateTime date = (DateTime)arg;
switch(format)
{
case "mycustomformat":
switch(CultureInfo.CurrentCulture.Name)
{
case "en-GB":
return date.ToString("ddd dd MMM");
default:
return date.ToString("ddd MMM dd");
}
default:
throw new FormatException();
}
}
I was expecting to be able to use it in the DateTime.ToString(string format, IFormatProvider provider)
method like so, but :
DateTime d = new DateTime(2000, 1, 2);
string s = d.ToString("mycustomformat", new MyDateFormatProvider());
In that example, running in the US Culture, the result is "00cu0Ao00or0aA"
, apparently because the standard DateTime format strings are being interpreted.
However, when I use the same class in the following way:
DateTime d = new DateTime(2000, 1, 2);
string s = String.Format(new MyDateFormatProvider(), "{0:mycustomformat}", d);
I get what I expect, namely "Sun Jan 02"
I don't understand the different results. Could someone explain?
Thanks!
The short explanation is that while
lets you pass anything implementing
IFormatProvider
as one of it's parameters, it actually only supports 2 possible types implementingIFormatProvider
inside it's code:DateTimeFormatInfo
orCultureInfo
If your parameter cannot be casted (using
as
) as either or those, the method will default toCurrentCulture
.String.Format
is not limited by such bounds.Checking the
DateTime.ToString
method with Reflector shows that theDateTime
structure uses theDateTimeFormatInfo.GetInstance
method to get the provider to be used for formatting. TheDateTimeFormatInfo.GetInstance
requests a formatter of typeDateTimeFormatInfo
from the provider passed in, never forICustomFormmater
, so it only returns an instance of aDateTimeFormatInfo
orCultureInfo
if no provider is found. It seems that theDateTime.ToString
method does not honor theICustomFormatter
interface like theStringBuilder.Format
method does, as yourString.Format
example shows.I agree that the
DateTime.ToString
method should support theICustomFormatter
interface, but it does not seem to currently. This may all have changed or will change in .NET 4.0.Use extension method :)