¿Cómo utilizo DateTime.TryParse con un <DateTime> que admite valores NULL?

115

Quiero usar el método DateTime.TryParse para obtener el valor de fecha y hora de una cadena en un valor Nullable. Pero cuando intento esto:

DateTime? d;
bool success = DateTime.TryParse("some date text", out (DateTime)d);

el compilador me dice

El argumento 'out' no se clasifica como una variable

No estoy seguro de lo que tengo que hacer aquí. También probé:

out (DateTime)d.Value 

y eso tampoco funciona. ¿Algunas ideas?

Brian Sullivan
fuente

Respuestas:

123
DateTime? d=null;
DateTime d2;
bool success = DateTime.TryParse("some date text", out d2);
if (success) d=d2;

(Puede haber soluciones más elegantes, pero ¿por qué no hace simplemente algo como el anterior?)

Jason Kealey
fuente
3
Tienes razón, estaba buscando algo más de una sola línea para hacerlo, pero supongo que esto servirá. No me gusta crear esa variable temporal, se siente desordenado. : - / Parece que este escenario debería tener un mejor soporte.
Brian Sullivan
1
vea la sugerencia de Binary Worrier de psuedo-inline eso en un método de extensión.
David Alpert
4
¿Por qué está transmitiendo un DateTime a un DateTime? No es necesario volver a colocar d2 antes de pasarlo a TryParse.
Aaron Powell
@Slace - Actualicé la respuesta para incorporar su sugerencia.
Drew Noakes
@Jason Kealey Espero que esto ya se haya introducido en VS2012, de lo contrario tendré que seguir usando este buen código.
Pimenta
161

Como dice Jason, puede crear una variable del tipo correcto y pasarla. Es posible que desee encapsularlo en su propio método:

public static DateTime? TryParse(string text)
{
    DateTime date;
    if (DateTime.TryParse(text, out date))
    {
        return date;
    }
    else
    {
        return null;
    }
}

... o si te gusta el operador condicional:

public static DateTime? TryParse(string text)
{
    DateTime date;
    return DateTime.TryParse(text, out date) ? date : (DateTime?) null;
}

O en C # 7:

public static DateTime? TryParse(string text) =>
    DateTime.TryParse(text, out var date) ? date : (DateTime?) null;
Jon Skeet
fuente
5
Probablemente no debería discutir con The Skeet, pero ... debería llamar a su método Parse, ya que esperaría que un método llamado TryParse siga la convención TryParse y devuelva un booleano. ;-)
Myster
@Myster: Bueno, en ninguno de los casos sigue la convención existente exacta; aquellos que solían Parseesperar que regresara DateTimey arrojara una excepción en caso de falla, ¿verdad? Pero sí, puedes hacer lo que quieras ... y en Noda Time, he nombrado los métodos relevantes en su Parselugar.
Jon Skeet
1
La elsepalabra clave es innecesaria (en su primer ejemplo) ya que ifnunca se puede alcanzar el punto final del bloque.
Jeppe Stig Nielsen
1
@JeppeStigNielsen: Sí, es innecesario, pero puede ser estilísticamente preferible para la simetría. Es solo una preferencia personal (y tampoco soy consistente ...)
Jon Skeet
3
@Kiquenet: usar else deja más claro que se tomará una u otra ruta, y ambas regresan. Estoy en contra del código anidado masivamente, pero en este caso realmente no es un problema, en mi opinión.
Jon Skeet
20

Aquí hay una edición un poco concisa de lo que sugirió Jason:

DateTime? d; DateTime dt;
d = DateTime.TryParse(DateTime.Now.ToString(), out dt)? dt : (DateTime?)null;

fuente
18

No puedes porque Nullable<DateTime>es de un tipo diferente a DateTime. Necesitas escribir tu propia función para hacerlo,

public bool TryParse(string text, out Nullable<DateTime> nDate)
{
    DateTime date;
    bool isParsed = DateTime.TryParse(text, out date);
    if (isParsed)
        nDate = new Nullable<DateTime>(date);
    else
        nDate = new Nullable<DateTime>();
    return isParsed;
}

Espero que esto ayude :)

EDITAR: Se eliminó el método de extensión (obviamente) probado incorrectamente, porque (como lo señaló algún mal hoor) los métodos de extensión que intentan cambiar el parámetro "this" no funcionarán con los tipos de valor.

PD: El Bad Hoor en cuestión es un viejo amigo :)

Preocupado binario
fuente
No quieres iniciar la fecha [ya que la estás usando como un parámetro de salida] OK, ¡dejaré de ser quisquilloso!
Ruben Bartelink
No tengo un compilador, pero como DateTime es un tipo de valor, ¿el método de extensión se compila?
Ruben Bartelink
El resultado no regresa a menos que lo haga - [TestFixture] public class WhenExtending {[Test] public void TryParseShouldWork () {DateTime? x = nulo; var res = Externders. TryParse (x, "1/1/1990"); Assert.IsTrue (res)
Ruben Bartelink

; Afirmar que (x! = Nulo); }} falla en el Assert. Eso, es decir, el resultado no se modifica ya que DateTime es un tipo de valor (que siempre es una buena pregunta para eliminar en las pantallas del teléfono: D)
Ruben Bartelink
(obv, el primero (sin extensión) funcionará, pero debería estar fuera, no ref - y debería anular el resultado si no encaja con las API de TryXXX en general - Estoy bastante seguro de que FDG menciona eso. ¡Soy quisquilloso!
Ruben Bartelink
4

¿Qué hay de crear un método de extensión?

public static class NullableExtensions
{
    public static bool TryParse(this DateTime? dateTime, string dateString, out DateTime? result)
    {
        DateTime tempDate;
        if(! DateTime.TryParse(dateString,out tempDate))
        {
            result = null;
            return false;
        }

        result = tempDate;
        return true;

    }
}
user2687864
fuente
2
¿Para qué es ese primer parámetro dateTime? Nunca se usa.
Mike Zboray
1
@mikez: así es como funcionan los métodos de extensión, el compilador lo usa para saber que debería ser un método de extensión.
Erik Funkenbusch
3
@MystereMan Sé lo que es un método de extensión. Una firma más apropiada para un método de extensión sería DateTime? TryParse(this string dateString). Esta implementación es simplemente extraña.
Mike Zboray
3
@mikez - ¿entonces por qué preguntaste para qué era? ¿Por qué contaminar el espacio de nombres de cadenas cuando solo lo necesita para fecha y hora? El propósito es proporcionar un análogo a DateTime.TryParse que es DateTime .TryParse?
Erik Funkenbusch
1
@ErikFunkenbusch Este método de extensión no permitirá una sintaxis de llamada como (DateTime?).TryParse( ... )o Nullable<DateTime>.TryParse( ... ). Mike Z tiene razón, esta es una firma tonta del método.
Jeppe Stig Nielsen
1

No veo por qué Microsoft no manejó esto. Un pequeño método de utilidad inteligente para lidiar con esto (tuve el problema con int, pero reemplazar int con DateTime tendrá el mismo efecto, podría ser .....

    public static bool NullableValueTryParse(string text, out int? nInt)
    {
        int value;
        if (int.TryParse(text, out value))
        {
            nInt = value;
            return true;
        }
        else
        {
            nInt = null;
            return false;
        }
    }
JStrahl
fuente
1

Este es el delineador que estás buscando:

DateTime? d = DateTime.TryParse("some date text", out DateTime dt) ? dt : null;

Si desea convertirlo en un método de pseudoextensión TryParse adecuado, puede hacer esto:

public static bool TryParse(string text, out DateTime? dt)
{
    if (DateTime.TryParse(text, out DateTime date))
    {
        dt = date;
        return true;
    }
    else
    {
        dt = null;
        return false;
    }
}
cpcolella
fuente
@robnick ¿En qué se diferencia eso de lo que dije?
cpcolella
1
Ignore mi comentario anterior (¡he votado a favor de su solución!), Para el último C # necesitaba emitir el nulo: ¿DateTime? d = DateTime.TryParse (blah, out DateTime dt)? dt: (DateTime?) null;
robnick
1

Aquí hay una solución de una sola línea:

DateTime? d = DateTime.TryParse("text", out DateTime parseDate) ? parseDate : (DateTime?)null;
usuario1267054
fuente
-3

Alternativamente, si no le preocupa la posible excepción planteada, puede cambiar TryParse por Parse:

DateTime? d = DateTime.Parse("some valid text");

Aunque tampoco habrá un booleano que indique el éxito, podría ser práctico en algunas situaciones en las que se sabe que el texto de entrada siempre será válido.

monsieurgutix
fuente