¿Cómo puedo formatear un DateTime anulable con ToString ()?

226

¿Cómo puedo convertir el DateTime dt2 anulable en una cadena formateada?

DateTime dt = DateTime.Now;
Console.WriteLine(dt.ToString("yyyy-MM-dd hh:mm:ss")); //works

DateTime? dt2 = DateTime.Now;
Console.WriteLine(dt2.ToString("yyyy-MM-dd hh:mm:ss")); //gives following error:

sin sobrecarga al método ToString toma un argumento

Edward Tanguay
fuente
3
Hola, ¿te importaría revisar las respuestas aceptadas y actuales? Una respuesta actual más relevante podría ser más correcta.
iuliu.net

Respuestas:

335
Console.WriteLine(dt2 != null ? dt2.Value.ToString("yyyy-MM-dd hh:mm:ss") : "n/a"); 

EDITAR: como se indicó en otros comentarios, verifique que haya un valor no nulo.

Actualización: como se recomienda en los comentarios, método de extensión:

public static string ToString(this DateTime? dt, string format)
    => dt == null ? "n/a" : ((DateTime)dt).ToString(format);

Y a partir de C # 6, puede usar el operador condicional nulo para simplificar aún más el código. La siguiente expresión devolverá nulo si DateTime?es nulo.

dt2?.ToString("yyyy-MM-dd hh:mm:ss")
Blake Pettersson
fuente
26
Parece que me está pidiendo un método de extensión.
David Glenn
42
El valor es la clave
stuartdotnet
@David no es que la tarea no sea trivial ... stackoverflow.com/a/44683673/5043056
Sinjai
3
¿Estás listo para esto ... dt? .ToString ("dd / MMM / aaaa") ?? "" Grandes ventajas de C # 6
Tom McDonough
Error CS0029: ¿No se puede convertir implícitamente el tipo 'cadena' a 'System.DateTime?' (CS0029). .Net Core 2.0
Oracular Man
80

Probar esto para el tamaño:

El objeto dateTime real que desea formatear está en la propiedad dt.Value, y no en el objeto dt2 en sí.

DateTime? dt2 = DateTime.Now;
 Console.WriteLine(dt2.HasValue ? dt2.Value.ToString("yyyy-MM-dd hh:mm:ss") : "[N/A]");
Russ
fuente
36

Ustedes están sobre ingeniería todo esto y lo hacen mucho más complicado de lo que realmente es. Lo importante, deje de usar ToString y comience a usar el formato de cadena como string.Format o los métodos que admiten el formato de cadena como Console.WriteLine. Aquí está la solución preferida para esta pregunta. Este es también el más seguro.

Actualizar:

Actualizo los ejemplos con métodos actualizados del compilador de C # de hoy. operadores condicionales e interpolación de cadenas

DateTime? dt1 = DateTime.Now;
DateTime? dt2 = null;

Console.WriteLine("'{0:yyyy-MM-dd hh:mm:ss}'", dt1);
Console.WriteLine("'{0:yyyy-MM-dd hh:mm:ss}'", dt2);
// New C# 6 conditional operators (makes using .ToString safer if you must use it)
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators
Console.WriteLine(dt1?.ToString("yyyy-MM-dd hh:mm:ss"));
Console.WriteLine(dt2?.ToString("yyyy-MM-dd hh:mm:ss"));
// New C# 6 string interpolation
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated
Console.WriteLine($"'{dt1:yyyy-MM-dd hh:mm:ss}'");
Console.WriteLine($"'{dt2:yyyy-MM-dd hh:mm:ss}'");

Salida: (pongo comillas simples para que pueda ver que vuelve como una cadena vacía cuando es nulo)

'2019-04-09 08:01:39'
''
2019-04-09 08:01:39

'2019-04-09 08:01:39'
''
John C
fuente
30

Como otros han dicho, debe verificar si hay valores nulos antes de invocar ToString, pero para evitar repetirse, puede crear un método de extensión que haga eso, algo como:

public static class DateTimeExtensions {

  public static string ToStringOrDefault(this DateTime? source, string format, string defaultValue) {
    if (source != null) {
      return source.Value.ToString(format);
    }
    else {
      return String.IsNullOrEmpty(defaultValue) ?  String.Empty : defaultValue;
    }
  }

  public static string ToStringOrDefault(this DateTime? source, string format) {
       return ToStringOrDefault(source, format, null);
  }

}

Que se puede invocar como:

DateTime? dt = DateTime.Now;
dt.ToStringOrDefault("yyyy-MM-dd hh:mm:ss");  
dt.ToStringOrDefault("yyyy-MM-dd hh:mm:ss", "n/a");
dt = null;
dt.ToStringOrDefault("yyyy-MM-dd hh:mm:ss", "n/a")  //outputs 'n/a'
David Glenn
fuente
28

C # 6.0 bebé:

dt2?.ToString("dd/MM/yyyy");

iuliu.net
fuente
2
Sugeriría la siguiente versión para que esta respuesta sea equivalente a la respuesta aceptada existente para C # 6.0. Console.WriteLine(dt2?.ToString("yyyy-MM-dd hh:mm:ss" ?? "n/a");
Puede Bud
15

El problema con la formulación de una respuesta a esta pregunta es que no especifica la salida deseada cuando la fecha y hora anulable no tiene valor. El siguiente código saldrá DateTime.MinValueen tal caso y, a diferencia de la respuesta actualmente aceptada, no arrojará una excepción.

dt2.GetValueOrDefault().ToString(format);
Matt Howells
fuente
7

Al ver que realmente desea proporcionar el formato, le sugiero que agregue la interfaz IFormattable al método de extensión Smalls de esta manera, de esa manera no tiene la concatenación de formato de cadena desagradable.

public static string ToString<T>(this T? variable, string format, string nullValue = null)
where T: struct, IFormattable
{
  return (variable.HasValue) 
         ? variable.Value.ToString(format, null) 
         : nullValue;          //variable was null so return this value instead   
}
ElmarG
fuente
6

¿Qué pasa con algo tan fácil como esto?

String.Format("{0:dd/MM/yyyy}", d2)
Max Brown
fuente
5

Puede usar dt2.Value.ToString("format"), pero, por supuesto, eso requiere que dt2! = Null, y eso niega el uso de un tipo anulable en primer lugar.

Aquí hay varias soluciones, pero la gran pregunta es: ¿cómo desea formatear una nullfecha?

Henk Holterman
fuente
5

Aquí hay un enfoque más genérico. Esto le permitirá formatear en cadena cualquier tipo de valor anulable. He incluido el segundo método para permitir reemplazar el valor de cadena predeterminado en lugar de usar el valor predeterminado para el tipo de valor.

public static class ExtensionMethods
{
    public static string ToString<T>(this Nullable<T> nullable, string format) where T : struct
    {
        return String.Format("{0:" + format + "}", nullable.GetValueOrDefault());
    }

    public static string ToString<T>(this Nullable<T> nullable, string format, string defaultValue) where T : struct
    {
        if (nullable.HasValue) {
            return String.Format("{0:" + format + "}", nullable.Value);
        }

        return defaultValue;
    }
}
Schmalls
fuente
4

Respuesta más corta

$"{dt:yyyy-MM-dd hh:mm:ss}"

Pruebas

DateTime dt1 = DateTime.Now;
Console.Write("Test 1: ");
Console.WriteLine($"{dt1:yyyy-MM-dd hh:mm:ss}"); //works

DateTime? dt2 = DateTime.Now;
Console.Write("Test 2: ");
Console.WriteLine($"{dt2:yyyy-MM-dd hh:mm:ss}"); //Works

DateTime? dt3 = null;
Console.Write("Test 3: ");
Console.WriteLine($"{dt3:yyyy-MM-dd hh:mm:ss}"); //Works - Returns empty string

Output
Test 1: 2017-08-03 12:38:57
Test 2: 2017-08-03 12:38:57
Test 3: 
drobertson
fuente
4

Incluso una mejor solución en C # 6.0:

DateTime? birthdate;

birthdate?.ToString("dd/MM/yyyy");
Mohammed Noureldin
fuente
4

Sintaxis de RAZOR:

@(myNullableDateTime?.ToString("yyyy-MM-dd") ?? String.Empty)
wut
fuente
2

Creo que tienes que usar GetValueOrDefault-Methode. El comportamiento con ToString ("aa ...") no está definido si la instancia es nula.

dt2.GetValueOrDefault().ToString("yyy...");
martín
fuente
1
El comportamiento con ToString ("aa ...") se define si la instancia es nula, porque GetValueOrDefault () devolverá DateTime.MinValue
Lucas
2

Aquí está la excelente respuesta de Blake como método de extensión. Agregue esto a su proyecto y las llamadas en la pregunta funcionarán como se esperaba.
Lo que significa que se usa como MyNullableDateTime.ToString("dd/MM/yyyy"), con el mismo resultado que MyDateTime.ToString("dd/MM/yyyy"), excepto que el valor será "N/A"si DateTime es nulo.

public static string ToString(this DateTime? date, string format)
{
    return date != null ? date.Value.ToString(format) : "N/A";
}
Sinjai
fuente
1

IFormattable también incluye un proveedor de formatos que se puede usar, permite que ambos formatos de IFormatProvider sean nulos en dotnet 4.0, esto sería

/// <summary>
/// Extentionclass for a nullable structs
/// </summary>
public static class NullableStructExtensions {

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <param name="provider">The format provider 
    /// If <c>null</c> the default provider is used</param>
    /// <param name="defaultValue">The string to show when the source is <c>null</c>. 
    /// If <c>null</c> an empty string is returned</param>
    /// <returns>The formatted string or the default value if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, string format = null, 
                                     IFormatProvider provider = null, 
                                     string defaultValue = null) 
                                     where T : struct, IFormattable {
        return source.HasValue
                   ? source.Value.ToString(format, provider)
                   : (String.IsNullOrEmpty(defaultValue) ? String.Empty : defaultValue);
    }
}

usando junto con parámetros con nombre que puedes hacer:

dt2.ToString (Valor predeterminado: "n / a");

En versiones anteriores de dotnet obtienes muchas sobrecargas

/// <summary>
/// Extentionclass for a nullable structs
/// </summary>
public static class NullableStructExtensions {

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <param name="provider">The format provider 
    /// If <c>null</c> the default provider is used</param>
    /// <param name="defaultValue">The string to show when the source is <c>null</c>. 
    /// If <c>null</c> an empty string is returned</param>
    /// <returns>The formatted string or the default value if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, string format, 
                                     IFormatProvider provider, string defaultValue) 
                                     where T : struct, IFormattable {
        return source.HasValue
                   ? source.Value.ToString(format, provider)
                   : (String.IsNullOrEmpty(defaultValue) ? String.Empty : defaultValue);
    }

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <param name="defaultValue">The string to show when the source is null. If <c>null</c> an empty string is returned</param>
    /// <returns>The formatted string or the default value if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, string format, string defaultValue) 
                                     where T : struct, IFormattable {
        return ToString(source, format, null, defaultValue);
    }

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <param name="provider">The format provider (if <c>null</c> the default provider is used)</param>
    /// <returns>The formatted string or an empty string if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, string format, IFormatProvider provider)
                                     where T : struct, IFormattable {
        return ToString(source, format, provider, null);
    }

    /// <summary>
    /// Formats a nullable struct or returns an empty string
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <returns>The formatted string or an empty string if the source is null</returns>
    public static string ToString<T>(this T? source, string format)
                                     where T : struct, IFormattable {
        return ToString(source, format, null, null);
    }

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="provider">The format provider (if <c>null</c> the default provider is used)</param>
    /// <param name="defaultValue">The string to show when the source is <c>null</c>. If <c>null</c> an empty string is returned</param>
    /// <returns>The formatted string or the default value if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, IFormatProvider provider, string defaultValue)
                                     where T : struct, IFormattable {
        return ToString(source, null, provider, defaultValue);
    }

    /// <summary>
    /// Formats a nullable struct or returns an empty string
    /// </summary>
    /// <param name="source"></param>
    /// <param name="provider">The format provider (if <c>null</c> the default provider is used)</param>
    /// <returns>The formatted string or an empty string if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, IFormatProvider provider)
                                     where T : struct, IFormattable {
        return ToString(source, null, provider, null);
    }

    /// <summary>
    /// Formats a nullable struct or returns an empty string
    /// </summary>
    /// <param name="source"></param>
    /// <returns>The formatted string or an empty string if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source) 
                                     where T : struct, IFormattable {
        return ToString(source, null, null, null);
    }
}
JeroenH
fuente
1

Me gusta esta opcion:

Console.WriteLine(dt2?.ToString("yyyy-MM-dd hh:mm:ss") ?? "n/a");
Martín
fuente
0

Extensiones genéricas simples

public static class Extensions
{

    /// <summary>
    /// Generic method for format nullable values
    /// </summary>
    /// <returns>Formated value or defaultValue</returns>
    public static string ToString<T>(this Nullable<T> nullable, string format, string defaultValue = null) where T : struct
    {
        if (nullable.HasValue)
        {
            return String.Format("{0:" + format + "}", nullable.Value);
        }

        return defaultValue;
    }
}
Andzej Maciusovic
fuente
-2

Tal vez sea una respuesta tardía, pero puede ayudar a cualquier otra persona.

Simple es:

nullabledatevariable.Value.Date.ToString("d")

o simplemente use cualquier formato en lugar de "d".

Mejor

Waleed
fuente
1
Esto generará un error cuando nullabledatevariable.Value sea nulo.
John C
-2

puedes usar una línea simple:

dt2.ToString("d MMM yyyy") ?? ""
Daniel Heo
fuente