Подключаемые / расширяемые String.Format и DateTimeFormatInfo?

Так, например, скажем, когда я форматирую дату и использую строку «или» в шаблоне формата, я хочу, чтобы она была преобразована в порядковое значение даты.

ie

string.Format("{0:ddor MMM yyyy}.", DateTime.Now)

должен выводить

1st Jan 2010

См. Ниже, как получить порядковые числа.

Есть ли в .NET простой способ получить окончания st, nd, rd и th для чисел?


person Simon    schedule 13.10.2010    source источник


Ответы (2)


Вроде нет ничего подобного.

Наиболее рекомендуемый способ сделать это:

var d = DateTime.Now;
var result2 = String.Format("{0:dd}{1} {2:MMM yyyy}", d, Ordinal(d.Day), d);

Очень хитрый способ добиться этого - создать собственный IFormatProvider. ИМО, это просто большая проблема, но просто чтобы показать альтернативный способ ... (у меня нет большого опыта в этом, это может быть не очень "правильно")

using System;

namespace Test
{
    class Program
    {
        public static string Ordinal(int number)
        {
            string suffix = String.Empty;

            int ones = number % 10;
            int tens = (int)Math.Floor(number / 10M) % 10;

            if (tens == 1)
            {
                suffix = @"\t\h";
            }
            else
            {
                switch (ones)
                {
                    case 1:
                        suffix = @"\s\t";
                        break;

                    case 2:
                        suffix = @"\n\d";
                        break;

                    case 3:
                        suffix = @"\r\d";
                        break;

                    default:
                        suffix = @"\t\h";
                        break;
                }
            }
            return suffix;
        }

        public class MyFormat : IFormatProvider, ICustomFormatter
        {
            public object GetFormat(Type formatType)
            {
                return (formatType == typeof(ICustomFormatter)) ? this : null;

            }

            public string Format(string format, object arg, IFormatProvider formatProvider)
            {
                var d = (DateTime)arg;

                var or = Ordinal(d.Day);

                format = format.Replace("or", or);

                return d.ToString(format);
            }
        }
        static void Main(string[] args)
        {
            var result = String.Format(new MyFormat(), "{0:ddor MMM yyyy}.", DateTime.Now);

            return;
        }
    }
}

Дополнительная информация о настраиваемом IFormatProvider

person BrunoLM    schedule 13.10.2010
comment
Спасибо за ответ, Бруно. однако я искал метод, который не был бы настолько навязчивым для пользователя. - person Simon; 13.10.2010

Поставщики форматов являются подключаемыми, но, насколько мне известно, вы не можете настроить поставщика форматов по умолчанию для данного типа. Методы, которые принимают строки формата по соглашению, обычно также имеют перегрузку, которая принимает IFormatProvider. Вы можете реализовать два класса, такие как MyFormatProvider: IFormatProvider и MyCustomFormatter: ICustomFormatter.

Когда обрабатывается строка формата, такая как "{0: dd} {0: or} {0: MMM} {0: yyyy}", ваш ICustomFormatter будет вызываться 4 раза, с "dd" или "," MMM "и" гггг "в качестве параметров, чтобы можно было форматировать каждую часть отдельно. Вам просто нужно обработать случай «или», а остальное передать поставщику формата по умолчанию.

Однако при форматировании вызывающей стороне все равно потребуется передать экземпляр вашего поставщика настраиваемого формата. Например:

string str = String.Format(MyFormatProvider.Default, "{0:dd}{0:or} {0:MMM} {0:yyyy}", date);

Насколько я знаю, от этого требования никуда не деться. Некоторое время назад я искал лучший способ, когда я создал «относительную» строку формата DateTime, которая отображала DateTimes, например, «1 час назад», «3 дня назад» и т. Д. Не мог найти способа избежать необходимости явно передать мой пользовательский IFormatProvider.

person Josh    schedule 13.10.2010