如何为DateTime创建和使用自定义IFormatProvider?

我试图创建一个IFormatProvider实现,可以识别DateTime对象的自定义格式字符串。 这是我的实施:

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

我希望能够在DateTime.ToString(string format, IFormatProvider provider)方法中使用它,但是:

 DateTime d = new DateTime(2000, 1, 2); string s = d.ToString("mycustomformat", new MyDateFormatProvider()); 

在该示例中,在美国文化中运行,结果是"00cu0Ao00or0aA" ,显然是因为正在解释标准的DateTime格式字符串。

但是,当我以下列方式使用同一个类时:

 DateTime d = new DateTime(2000, 1, 2); string s = String.Format(new MyDateFormatProvider(), "{0:mycustomformat}", d); 

我得到了我的期望,即"Sun Jan 02"

我不明白不同的结果。 有人能解释一下吗

谢谢!

使用Reflector检查DateTime.ToString方法显示DateTime结构使用DateTimeFormatInfo.GetInstance方法来获取要用于格式化的提供程序。 DateTimeFormatInfo从传入的提供程序请求类型为DateTimeFormatInfo的格式化程序,从不为ICustomFormmater ,因此如果找不到提供程序,它只返回DateTimeFormatInfoCultureInfo的实例。 看起来DateTime.ToString方法不像StringBuilder.Format方法那样遵守ICustomFormatter接口,正如您的String.Format示例所示。

我同意DateTime.ToString方法应该支持ICustomFormatter接口,但它目前似乎不是。 这可能已经改变或将在.NET 4.0中发生变化。

简短的解释是,虽然

 DateTime.ToString(string format, IFormatProvider provider) 

允许您将实现IFormatProvider任何内容作为其中一个参数传递,它实际上只支持在其代码中实现IFormatProvider 2种可能类型:

DateTimeFormatInfoCultureInfo

如果您的参数不能(或使用as )作为其中任何一个或那些参数,则该方法将默认为CurrentCulture

String.Format不受此类限制的限制。

使用扩展方法:)

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