开发者

How to create and use a custom IFormatProvider for DateTime?

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 Ge开发者_开发技巧tFormat(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

DateTime.ToString(string format, IFormatProvider provider)

lets you pass anything implementing IFormatProvider as one of its parameters, it actually only supports 2 possible types implementing IFormatProvider inside its 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.


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.


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);
        }
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜