Cómo crear y utilizar un IFormatProvider personalizado para DateTime?
-
24-09-2019 - |
Pregunta
Yo estaba tratando de crear una implementación IFormatProvider
que reconocería las cadenas de formato personalizado para objetos DateTime. Aquí está mi aplicación:
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();
}
}
Me estaba esperando a ser capaz de utilizarlo en el método DateTime.ToString(string format, IFormatProvider provider)
como tal, sino que:
DateTime d = new DateTime(2000, 1, 2);
string s = d.ToString("mycustomformat", new MyDateFormatProvider());
En este ejemplo, se ejecuta en la cultura de Estados Unidos, el resultado es "00cu0Ao00or0aA"
, al parecer porque las cadenas de formato estándar DateTime se interpretan.
Sin embargo, cuando se utiliza la misma clase de la siguiente manera:
DateTime d = new DateTime(2000, 1, 2);
string s = String.Format(new MyDateFormatProvider(), "{0:mycustomformat}", d);
consigo lo que esperaba, a saber "Sun Jan 02"
No entiendo los diferentes resultados. Podría explicar alguien?
Gracias!
Solución
Comprobación del método DateTime.ToString
con espectáculos Reflector que la estructura DateTime
utiliza el método DateTimeFormatInfo.GetInstance
para obtener el proveedor que se utiliza para formatear. El DateTimeFormatInfo.GetInstance
solicita un formateador de tipo DateTimeFormatInfo
del proveedor aprobada en, nunca por ICustomFormmater
, por lo que sólo devuelve una instancia de un DateTimeFormatInfo
o CultureInfo
si no se encuentra ningún proveedor. Parece que el método DateTime.ToString
no respeta la interfaz ICustomFormatter
como el método StringBuilder.Format
hace, como sus String.Format
ejemplo muestra.
Estoy de acuerdo que el método DateTime.ToString
debe apoyar la interfaz ICustomFormatter
, pero no parece actualmente. Todo esto puede haber cambiado o cambiará en .NET 4.0.
Otros consejos
La breve explicación es que mientras
DateTime.ToString(string format, IFormatProvider provider)
permite pasar nada implementación IFormatProvider
como uno de sus parámetros, que en realidad sólo admite 2 tipos posibles IFormatProvider
implementar dentro del código:
DateTimeFormatInfo
o CultureInfo
Si el parámetro no se puede lanzar (usando as
), ya sea como o aquellos, el método será por defecto CurrentCulture
.
String.Format
no está limitada por tales límites.
método Uso extensión:)
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);
}
}