views:

27

answers:

2

So for example lets say when I string.format a date and use the string "or" in format pattern I want that converted to the ordinal value of the Date.

ie

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

should output

1st Jan 2010

See below for how to derive the ordinal numbers

http://stackoverflow.com/questions/69262/is-there-an-easy-way-in-net-to-get-st-nd-rd-and-th-endings-for-numbers/69328#69328

+2  A: 

It seems there isn't something like it.

The most recommended way to do it:

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

A very hacky way to achieve it is to create a custom IFormatProvider. IMO it's just a lot of trouble, but just to show an alternative way... (I don't have much experience with this, It might not be very "correct")

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

More info on Custom IFormatProvider

BrunoLM
Thanks for the answer Bruno. however i was looking for a method that was not so intrusive to the user.
Simon
+1  A: 

Format providers are pluggable, but as far as I know, you can't set up a default format provider for a given type. Methods that take format strings by convention typically also have an overload that takes an IFormatProvider. You can implement two classes such as MyFormatProvider : IFormatProvider and MyCustomFormatter : ICustomFormatter.

When a format string such as "{0:dd}{0:or} {0:MMM} {0:yyyy}" is processed, your ICustomFormatter will be called 4 times, with "dd", "or", "MMM", and "yyyy" as the parameters so it can format each part separately. You would simply have to handle the "or" case and pass the rest onto the default format provider.

However, the caller will still need to pass in an instance of your custom format provider when formatting. For example:

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

As far as I know, there's no escaping that requirement. I searched for a better way a while back when I had created a "relative" DateTime format string that displayed DateTimes like "1 hour ago", "3 days ago", etc. Couldn't figure out a way to avoid having to explicitly pass my custom IFormatProvider.

Josh Einstein