Как создать и использовать пользовательский 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);
        }
    }
Другие вопросы по тегам