c# - fecha - datetime format
¿Cómo crear y usar un IFormatProvider personalizado para DateTime? (3)
Estaba intentando crear una implementación de IFormatProvider
que reconociera cadenas de formato personalizado para los objetos DateTime. Aquí está mi implementació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();
}
}
Esperaba poder usarlo en el método DateTime.ToString(string format, IFormatProvider provider)
, pero:
DateTime d = new DateTime(2000, 1, 2);
string s = d.ToString("mycustomformat", new MyDateFormatProvider());
En ese ejemplo, al ejecutarse en la Cultura de EE. UU., El resultado es "00cu0Ao00or0aA"
, aparentemente porque se están interpretando las cadenas de formato de fecha y "00cu0Ao00or0aA"
estándar.
Sin embargo, cuando uso la misma clase de la siguiente manera:
DateTime d = new DateTime(2000, 1, 2);
string s = String.Format(new MyDateFormatProvider(), "{0:mycustomformat}", d);
Obtengo lo que espero, a saber, "Sun Jan 02"
No entiendo los diferentes resultados. ¿Podría alguien explicar?
¡Gracias!
La breve explicación es que mientras
DateTime.ToString(string format, IFormatProvider provider)
le permite pasar cualquier cosa que implemente IFormatProvider
como uno de sus parámetros, en realidad solo admite 2 tipos posibles que implementan IFormatProvider
dentro de su código:
DateTimeFormatInfo
o CultureInfo
Si su parámetro no se puede convertir (usando as
) como ninguno de estos, el método se establecerá de forma predeterminada en CurrentCulture
.
String.Format
no está limitado por tales límites.
La comprobación del método DateTime.ToString
con Reflector muestra que la estructura DateTime
utiliza el método DateTimeFormatInfo.GetInstance
para que el proveedor se utilice para el formateo. DateTimeFormatInfo.GetInstance
solicita un formateador de tipo DateTimeFormatInfo
del proveedor que se le ICustomFormmater
, nunca para ICustomFormmater
, por lo que solo devuelve una instancia de DateTimeFormatInfo
o CultureInfo
si no se encuentra ningún proveedor. Parece que el método DateTime.ToString
no ICustomFormatter
interfaz ICustomFormatter
como lo hace el método StringBuilder.Format
, como muestra el ejemplo de String.Format
.
Estoy de acuerdo en que el método DateTime.ToString
debe ser compatible con la interfaz ICustomFormatter
, pero no parece que actualmente. Todo esto puede haber cambiado o cambiará en .NET 4.0.
Usa el método de 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);
}
}