Как создать и использовать пользовательский IFormatProvider для DateTime?
Я пытался создать 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"
Я не понимаю разные результаты. Может кто-нибудь объяснить?
Спасибо!
3 ответа
Проверка DateTime.ToString
Метод с отражателем показывает, что DateTime
структура использует DateTimeFormatInfo.GetInstance
метод получения провайдера для форматирования. DateTimeFormatInfo.GetInstance
запрашивает форматировщик типа DateTimeFormatInfo
от провайдера перешел, ни разу за ICustomFormmater
, так что он возвращает только экземпляр DateTimeFormatInfo
или же CultureInfo
если провайдер не найден Кажется, что DateTime.ToString
метод не соблюдает ICustomFormatter
интерфейс как StringBuilder.Format
метод делает, как ваш String.Format
пример показывает.
Я согласен, что DateTime.ToString
метод должен поддерживать ICustomFormatter
интерфейс, но это не похоже на данный момент. Возможно, все изменилось или изменится в.NET 4.0.
Краткое объяснение заключается в том, что в то время как
DateTime.ToString(string format, IFormatProvider provider)
позволяет передавать что-либо реализации IFormatProvider
как один из его параметров, он на самом деле поддерживает только 2 возможных типа реализации IFormatProvider
внутри это код:
DateTimeFormatInfo
или же CultureInfo
Если ваш параметр не может быть приведен (используя 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);
}
}