Comment créer et utiliser un IFormatProvider personnalisé pour DateTime?
-
24-09-2019 - |
Question
Je suis en train de créer une implémentation IFormatProvider
qui reconnaîtrait les chaînes de format personnalisé pour les objets DateTime. Voici mon implémentation:
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 comptais pouvoir l'utiliser dans la méthode DateTime.ToString(string format, IFormatProvider provider)
comme si, mais:
DateTime d = new DateTime(2000, 1, 2);
string s = d.ToString("mycustomformat", new MyDateFormatProvider());
Dans cet exemple, en cours d'exécution dans la culture des États-Unis, le résultat est "00cu0Ao00or0aA"
, apparemment parce que les chaînes au format standard DateTime sont interprétées.
Cependant, quand 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);
Je reçois ce que je pense, à savoir "Sun Jan 02"
Je ne comprends pas les différents résultats. Quelqu'un pourrait-il expliquer?
Merci!
La solution
Vérification de la méthode DateTime.ToString
avec réflecteur montre que la structure de DateTime
utilise la méthode DateTimeFormatInfo.GetInstance
pour obtenir le fournisseur à utiliser pour le formatage. Le DateTimeFormatInfo.GetInstance
demande un formatter de type DateTimeFormatInfo
du fournisseur transmis, jamais pour ICustomFormmater
, il retourne seulement une instance d'un DateTimeFormatInfo
ou CultureInfo
si aucun fournisseur se trouve. Il semble que la méthode DateTime.ToString
ne respecte pas l'interface ICustomFormatter
comme la méthode StringBuilder.Format
fait, comme exemple de String.Format
montre.
Je suis d'accord que la méthode DateTime.ToString
doit supporter l'interface ICustomFormatter
, mais il ne semble pas actuellement. Tout cela peut être changé ou va changer dans .NET 4.0.
Autres conseils
L'explication courte est que tout
DateTime.ToString(string format, IFormatProvider provider)
vous permet de transmettre quoi que ce soit la mise en œuvre IFormatProvider
comme l'un de ses paramètres, il prend en charge en fait seulement 2 types possibles de mise en œuvre IFormatProvider
dans son code:
DateTimeFormatInfo
ou CultureInfo
Si votre paramètre ne peut pas être casté (en utilisant as
) comme l'un ou ceux, la méthode par défaut CurrentCulture
.
String.Format
ne se limite pas par de telles limites.
Utilisation 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);
}
}