Являются ли String.Format и DateTimeFormatInfo подключаемыми / расширяемыми? - PullRequest
1 голос
/ 13 октября 2010

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

т.е.

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

1st Jan 2010

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

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

Ответы [ 2 ]

2 голосов
/ 13 октября 2010

Кажется, что-то не так.

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

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

Более подробная информация о Custom IFormatProvider

1 голос
/ 13 октября 2010

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

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

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

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

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

...