Is String.Format and DateTimeFormatInfo pluggable/extensible?
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 开发者_JAVA技巧Date.
ie
string.Format("{0:ddor MMM yyyy}.", DateTime.Now)
should output
1st Jan 2010
See below for how to derive the ordinal numbers
Is there an easy way in .NET to get "st", "nd", "rd" and "th" endings for numbers?
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
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.
精彩评论