问题
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!
回答1:
Checking the DateTime.ToString
method with Reflector shows that the DateTime
structure uses the DateTimeFormatInfo.GetInstance
method to get the provider to be used for formatting. The DateTimeFormatInfo.GetInstance
requests a formatter of type DateTimeFormatInfo
from the provider passed in, never for ICustomFormmater
, so it only returns an instance of a DateTimeFormatInfo
or CultureInfo
if no provider is found. It seems that the DateTime.ToString
method does not honor the ICustomFormatter
interface like the StringBuilder.Format
method does, as your String.Format
example shows.
I agree that the DateTime.ToString
method should support the ICustomFormatter
interface, but it does not seem to currently. This may all have changed or will change in .NET 4.0.
回答2:
The short explanation is that while
DateTime.ToString(string format, IFormatProvider provider)
lets you pass anything implementing IFormatProvider
as one of it's parameters, it actually only supports 2 possible types implementing IFormatProvider
inside it's code:
DateTimeFormatInfo
or CultureInfo
If your parameter cannot be casted (using as
) as either or those, the method will default to CurrentCulture
.
String.Format
is not limited by such bounds.
回答3:
Use extension method :)
public static class FormatProviderExtension
{
public static string FormatIt(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();
}
}
public static string ToString(this DateTime d, IFormatProvider formatProvider, string format)
{
return FormatIt(format, d, formatProvider);
}
}
来源:https://stackoverflow.com/questions/2382154/how-to-create-and-use-a-custom-iformatprovider-for-datetime