J'essayais de créer une implémentation IFormatProvider
qui reconnaîtrait les chaînes de format personnalisées pour les objets DateTime. Voici ma mise en œuvre:
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();
}
}
Je m'attendais à pouvoir l'utiliser dans la méthode DateTime.ToString(string format, IFormatProvider provider)
comme ça, mais:
DateTime d = new DateTime(2000, 1, 2);
string s = d.ToString("mycustomformat", new MyDateFormatProvider());
Dans cet exemple, exécuté dans la culture américaine, le résultat est "00cu0Ao00or0aA"
, Apparemment parce que les chaînes de format DateTime standard sont interprétées.
Cependant, lorsque j'utilise la même classe de la manière suivante:
DateTime d = new DateTime(2000, 1, 2);
string s = String.Format(new MyDateFormatProvider(), "{0:mycustomformat}", d);
J'obtiens ce que j'attends, à savoir "Sun Jan 02"
Je ne comprends pas les différents résultats. Quelqu'un pourrait-il expliquer?
Merci!
Vérification du DateTime.ToString
avec Reflector montre que la structure DateTime
utilise le DateTimeFormatInfo.GetInstance
méthode pour obtenir le fournisseur à utiliser pour le formatage. Le DateTimeFormatInfo.GetInstance
demande un formateur de type DateTimeFormatInfo
au fournisseur passé, jamais pour ICustomFormmater
, donc il ne retourne qu'une instance de DateTimeFormatInfo
ou CultureInfo
si aucun fournisseur n'est trouvé. Il semble que le DateTime.ToString
ne respecte pas l'interface ICustomFormatter
comme le StringBuilder.Format
fait, comme votre String.Format
montre l'exemple.
Je reconnais que le DateTime.ToString
devrait prendre en charge l'interface ICustomFormatter
, mais cela ne semble pas le faire actuellement. Tout cela peut avoir changé ou changera dans .NET 4.0.
La brève explication est que si
DateTime.ToString(string format, IFormatProvider provider)
vous permet de passer tout ce qui implémente IFormatProvider
comme l'un de ses paramètres, il ne supporte en fait que 2 types possibles implémentant IFormatProvider
dans son code:
DateTimeFormatInfo
ou CultureInfo
Si votre paramètre ne peut pas être converti (en utilisant as
) comme l'un ou l'autre, la méthode sera par défaut CurrentCulture
.
String.Format
n'est pas limité par de telles limites.
Utilisez la méthode d'extension :)
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);
}
}