Valore "null" di DateTime


273

Ho cercato molto ma non sono riuscito a trovare una soluzione. Come gestisci un DateTime che dovrebbe essere in grado di contenere un valore non inizializzato (equivalente a null)? Ho una classe che potrebbe avere un valore di proprietà DateTime impostato o meno. Stavo pensando di inizializzare il titolare della proprietà su DateTime.MinValue, che poi poteva essere facilmente controllato. Immagino che questa sia una domanda abbastanza comune, come si fa?

Risposte:


420

Per i DateTime normali, se non li inizializzi affatto, corrisponderanno DateTime.MinValueperché è un tipo di valore anziché un tipo di riferimento.

Puoi anche usare un DateTime nullable, in questo modo:

DateTime? MyNullableDate;

O la forma più lunga:

Nullable<DateTime> MyNullableDate;

E, infine, c'è un modo integrato per fare riferimento al valore predefinito di qualsiasi tipo. Questo restituisce nullper i tipi di riferimento, ma per il nostro esempio DateTime restituirà lo stesso di DateTime.MinValue:

default(DateTime)

o, nelle versioni più recenti di C #,

default

8
Sarebbe di grande aiuto se fornissi un esempio di come usarlo. Come si assegna il DateTime nel database, che potrebbe essere DBNull, al DateTime nullable?
kirk.burleson,

9
È anche bello notare che quando li inizializzi e con null, vengono assegnati DateTime.MinValueanche loro
Jeff LaFay,

2
@ kirk.burleson che sembra una domanda separata.
CompuChip,

dovrai MyNullableDate=date; impostarlo, MyDate = MyNullableDate.Value;leggere da esso e if(MyNullableDate.HasValue)verificare se è nullo
satibel

Per chiarire un po '"finalmente" la risposta - il valore predefinito di Nullable <DateTime> (DateTime?) È nullo, poiché Nullable <T> crea un tipo di riferimento.
Ryanwebjackson,

88

Se stai usando .NET 2.0 (o successivo) puoi usare il tipo nullable:

DateTime? dt = null;

o

Nullable<DateTime> dt = null;

poi più tardi:

dt = new DateTime();

E puoi controllare il valore con:

if (dt.HasValue)
{
  // Do something with dt.Value
}

Oppure puoi usarlo come:

DateTime dt2 = dt ?? DateTime.MinValue;

Puoi leggere di più qui:
http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx


1
È possibile utilizzare tipi nullable anche nelle versioni precedenti di .NET, senza bisogno di 3.0.
stephenbayer,

1
È arrivato in .NET 2.0 giusto? Il ? la sintassi è stata aggiunta a VB.NET in 3.5, ma è stata in C # dal 2.0 credo.
David Mohundro,

1
I tipi nullable sono disponibili in .Net 2.0. C # ha avuto la stenografia? notazione dalla 2.0. Solo VB.Net non aveva la stenografia? nel 2.0 ma potresti usare Nullable (Of DateTime)
Mendelt il

Per l'ultimo frammento, direi DateTime dt2 = dt ?? DateTime.MinValue;
Joel Coehoorn,

Vorrei usare dt.GetValueOrDefault()- è l'opzione più efficiente.
CompuChip,

37

Appuntamento? MyDateTime {get; set;}

MyDateTime = (dr["f1"] == DBNull.Value) ? (DateTime?)null : ((DateTime)dr["f1"]);

1
Questo mi ha aiutato a scoprire che passare nullnon funziona. Deve esserlo (DateTime?)null.
Inphinite Phractals,

33

Anche il modo seguente funziona

myClass.PublishDate = toPublish ? DateTime.Now : (DateTime?)null;

La proprietà PublishDate dovrebbe essere DateTime?



8

Vale la pena sottolineare che, sebbene una DateTimevariabile non possa essere null, può comunque essere confrontata nullsenza un errore del compilatore:

DateTime date;
...
if(date == null) // <-- will never be 'true'
  ...

6

È possibile utilizzare una classe nullable.

DateTime? date = new DateTime?();

Probabilmente vale la pena notare che questo ti darà un comportamento diverso rispetto all'istanza di un non annullabile DateTime. Come accennato in precedenza, new DateTime()ti darà effettivamente DateTime.Minmentre new DateTime?()si tradurrà in null.
Vitoc,

6

È possibile utilizzare un DateTime nullable per questo.

Nullable<DateTime> myDateTime;

o la stessa cosa scritta così:

DateTime? myDateTime;

6

È possibile impostare DateTime su Nullable. Per impostazione predefinita, DateTime non è nullable. Puoi renderlo nullable in un paio di modi. Usando un punto interrogativo dopo il tipo DateTime? myTime o usando lo stile generico Nullable.

DateTime? nullDate = null;

o

DateTime? nullDate;

5

Ho sempre impostato il tempo per DateTime.MinValue. In questo modo non ottengo alcuna NullErrorException e posso confrontarlo con una data che so non è impostata.


8
Ciò significa che non puoi distinguere tra "Ho davvero bisogno di un DateTime qui" e "È facoltativo" - Nullable <DateTime> è una soluzione molto migliore, IMO.
Jon Skeet,

? Davvero non capisco il tuo commento. Sì, so quando il DateTime è così lontano dalla realtà è come se fosse nullo ...
Patrick Desjardins,

2
È conveniente, ma vedo DateTime.MinValue come un valore, non come una condizione del caso speciale. Può solo portare a problemi lungo la linea. Andrei con Nullable <DateTime>.
spoulson,

3
Penso che ti manchi qualcosa della mia risposta, Spoulson ha scritto qualcosa e io stavo rispondendo. A proposito di membri pubblici, beh non è lo stesso e tu lo sai. è come String.Empty o null. Puoi fare entrambe le cose, non perché String.Empty è meglio che null sia sbagliato. Qualunque cosa.
Patrick Desjardins,

1
Sono con Daok su questo. Potrebbe non essere l'approccio "dal libro" ma è meglio che ottenere una NullReferenceException o gestire il tipo Nullable ingombrante. Inoltre, quante applicazioni ci sono che devono effettivamente fare riferimento alla data 1 gennaio 1 d.C.?
Jacobs Data Solutions,

4

Basta essere avvisati: quando si utilizza una Nullable, ovviamente non è più un oggetto datetime "puro", pertanto non è possibile accedere direttamente ai membri DateTime. Proverò a spiegare.

Usando Nullable <> stai fondamentalmente racchiudendo DateTime in un contenitore (grazie generici) di cui è nullable - ovviamente il suo scopo. Questo contenitore ha le sue proprietà che è possibile chiamare che forniranno l'accesso al suddetto oggetto DateTime; dopo aver usato la proprietà corretta - in questo caso Nullable.Value - avrai quindi accesso ai membri DateTime standard, alle proprietà ecc.

Quindi - ora viene in mente il problema sul modo migliore per accedere all'oggetto DateTime. Ci sono alcuni modi, il numero 1 è di gran lunga il migliore e 2 è "amico perché".

  1. Utilizzando la proprietà Nullable.Value,

    DateTime date = myNullableObject.Value.ToUniversalTime(); //Works

    DateTime date = myNullableObject.ToUniversalTime(); //Not a datetime object, fails

  2. Conversione dell'oggetto nullable in datetime utilizzando Convert.ToDateTime (),

    DateTime date = Convert.ToDateTime(myNullableObject).ToUniversalTime(); //works but why...

Sebbene la risposta sia ben documentata a questo punto, credo che valga la pena postare l'uso di Nullable. Scusa se non sei d'accordo.

modifica: rimossa una terza opzione poiché era un po 'troppo specifica e dipendente dal caso.


2

Sebbene tutti ti abbiano già dato la risposta, menzionerò un modo che semplifica il passaggio di un datetime in una funzione

[ERRORE: impossibile convertire system.datetime? a system.datetime]

DateTime? dt = null;
DateTime dte = Convert.ToDateTime(dt);

Ora puoi passare dte all'interno della funzione senza problemi.


1

Se, a volte, ti aspetti un valore nullo, potresti usare qualcosa del genere:

var orderResults = Repository.GetOrders(id, (DateTime?)model.DateFrom, (DateTime?)model.DateTo)

Nel tuo repository usa datetime in grado di null.

public Orders[] GetOrders(string id, DateTime? dateFrom, DateTime? dateTo){...}

1

Ho avuto lo stesso problema che ho dovuto dare a Null come parametro per DateTime durante l'esecuzione di Unit test per Throws ArgumentNullException. Nel mio caso ha funzionato usando la seguente opzione:

Assert.Throws<ArgumentNullException>(()=>sut.StartingDate = DateTime.Parse(null));

0

Data la natura di un tipo di dati data / ora, non può contenere un nullvalore, ovvero deve contenere un valore, non può essere vuoto o contenere nulla. Se si contrassegna una variabile data / ora come nullablesolo allora è possibile assegnare un valore null ad essa. Quindi quello che stai cercando di fare è una delle due cose (potrebbe essercene di più ma posso solo pensare a due):

  • Assegna un valore data / ora minimo alla tua variabile se non ne hai un valore. Puoi anche assegnare un valore di data / ora massimo, a seconda del modo che preferisci. Assicurati solo di essere coerente in tutto il sito quando controlli i valori di data / ora. Decidi di usare mino maxe mantienilo.

  • Contrassegna la tua variabile data / ora come nullable. In questo modo è possibile impostare la variabile data / ora su nullse non si dispone di una variabile.

Vorrei dimostrare il mio primo punto usando un esempio. Il DateTimetipo di variabile non può essere impostato su null, ha bisogno di un valore, in questo caso lo imposterò sul DateTimevalore minimo se non c'è alcun valore.

Il mio scenario è che ho una BlogPostlezione. Ha molti campi / proprietà diversi ma ho scelto di usarne solo due per questo esempio. DatePublishedè quando il post è stato pubblicato sul sito Web e deve contenere un valore data / ora. DateModifiedè quando un post viene modificato, quindi non deve contenere un valore, ma può contenere un valore.

public class BlogPost : Entity
{
     public DateTime DateModified { get; set; }

     public DateTime DatePublished { get; set; }
}

Utilizzo ADO.NETper ottenere i dati dal database (assegnare DateTime.MinValuese non c'è valore):

BlogPost blogPost = new BlogPost();
blogPost.DateModified = sqlDataReader.IsDBNull(0) ? DateTime.MinValue : sqlDataReader.GetFieldValue<DateTime>(0);
blogPost.DatePublished = sqlDataReader.GetFieldValue<DateTime>(1);

Puoi realizzare il mio secondo punto contrassegnando il DateModifiedcampo come nullable. Ora puoi impostarlo su nullse non c'è valore per esso:

public DateTime? DateModified { get; set; }

Usando ADO.NETper ottenere i dati dal database, sembrerà un po 'diverso dal modo in cui è stato fatto sopra (assegnando nullinvece di DateTime.MinValue):

BlogPost blogPost = new BlogPost();
blogPost.DateModified = sqlDataReader.IsDBNull(0) ? (DateTime?)null : sqlDataReader.GetFieldValue<DateTime>(0);
blogPost.DatePublished = sqlDataReader.GetFieldValue<DateTime>(1);

Spero che questo aiuti a chiarire qualsiasi confusione. Dato che la mia risposta è circa 8 anni dopo, probabilmente ora sei un programmatore esperto C # :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.