DateTime „null” wartość

273

Dużo szukałem, ale nie mogłem znaleźć rozwiązania. Jak radzisz sobie z DateTime, który powinien być w stanie zawierać niezainicjowaną wartość (równoważną zeru)? Mam klasę, która może mieć ustawioną wartość właściwości DateTime lub nie. Zastanawiałem się nad zainicjowaniem właściciela właściwości na DateTime.MinValue, który następnie można łatwo sprawdzić. Myślę, że to dość częste pytanie, jak to robisz?

Maty
źródło

Odpowiedzi:

420

W przypadku zwykłych DateTimes, jeśli nie zainicjujesz ich wcale, będą one pasować DateTime.MinValue, ponieważ jest to typ wartości, a nie typ odwołania.

Możesz także użyć zerowej wartości DateTime, jak poniżej:

DateTime? MyNullableDate;

Lub dłuższa forma:

Nullable<DateTime> MyNullableDate;

I na koniec istnieje wbudowany sposób odwoływania się do wartości domyślnych dowolnego typu. Zwraca nulltypy referencyjne, ale w naszym przykładzie DateTime zwróci to samo, co DateTime.MinValue:

default(DateTime)

lub w nowszych wersjach C #

default
Joel Coehoorn
źródło
8
Byłoby to bardzo pomocne, jeśli podasz przykład, jak z niego korzystać. W jaki sposób przypisujesz DateTime w bazie danych, którym może być DBNull, do zerowego DateTime?
kirk.burleson
9
Jest to także dobry, aby pamiętać, że gdy zrobisz je iz zerową zainicjować, są one przypisane DateTime.MinValue, a także
Jeff LaFay
2
@ kirk.burleson, który wygląda jak osobne pytanie.
CompuChip,
musisz MyNullableDate=date; go ustawić, MyDate = MyNullableDate.Value;czytać i if(MyNullableDate.HasValue)sprawdzać, czy jest pusty
satibel,
Aby nieco wyjaśnić odpowiedź „w końcu” - domyślna wartość Nullable <DateTime> (DateTime?) Jest pusta, ponieważ Nullable <T> tworzy typ odwołania.
ryanwebjackson
88

Jeśli używasz platformy .NET 2.0 (lub nowszej), możesz użyć typu zerowalnego:

DateTime? dt = null;

lub

Nullable<DateTime> dt = null;

potem później:

dt = new DateTime();

Możesz sprawdzić wartość za pomocą:

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

Lub możesz użyć go w następujący sposób:

DateTime dt2 = dt ?? DateTime.MinValue;

Możesz przeczytać więcej tutaj:
http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx

Mark Ingram
źródło
1
Możesz używać typów zerowalnych nawet we wcześniejszych wersjach .NET, bez potrzeby 3.0.
stephenbayer
1
Przyszedł w .NET 2.0, prawda? The? składnia została dodana do VB.NET w wersji 3.5, ale jest w C # od wersji 2.0.
David Mohundro
1
Typy zerowalne są dostępne w .Net 2.0. C # miał skrót? notacja z 2.0. Tylko VB.Net nie miał stenografii? w wersji 2.0, ale można użyć Nullable (Of DateTime)
Mendelt
W przypadku ostatniego fragmentu powiedziałbym, że DateTime dt2 = dt ?? DateTime.MinValue;
Joel Coehoorn
Chciałbym użyć dt.GetValueOrDefault()- to najbardziej wydajna opcja.
CompuChip
37

Data i godzina? MyDateTime {get; set;}

MyDateTime = (dr["f1"] == DBNull.Value) ? (DateTime?)null : ((DateTime)dr["f1"]);
Iman
źródło
1
To pomogło mi odkryć, że przekazywanie po prostu nullnie działa. To musi być (DateTime?)null.
Inphinite Phractals
33

Następujący sposób również działa

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

Należy pamiętać, że właściwość PublishDate powinna mieć datę i godzinę?

Aleksei
źródło
8

Warto zauważyć, że chociaż DateTimezmienna nie może być null, nadal można ją porównać nullbez błędu kompilatora:

DateTime date;
...
if(date == null) // <-- will never be 'true'
  ...
uncoder
źródło
6

Możesz użyć zerowalnej klasy.

DateTime? date = new DateTime?();
Aaron Smith
źródło
Prawdopodobnie warto zauważyć, że da to inne zachowanie niż tworzenie instancji, która nie ma wartości zerowej DateTime. Jak wcześniej wspomniano, new DateTime()skutecznie da ci, DateTime.Minpodczas gdy new DateTime?()spowoduje zero.
Vitoc
6

W tym celu można użyć zerowej wartości DateTime.

Nullable<DateTime> myDateTime;

lub to samo napisane w ten sposób:

DateTime? myDateTime;
Patrik Svensson
źródło
6

Możesz ustawić DateTime na Nullable. Domyślnie DateTime nie ma wartości zerowej. Możesz ustawić zerowanie na kilka sposobów. Używasz znaku zapytania po typie DateTime? myTime lub za pomocą ogólnego stylu Nullable.

DateTime? nullDate = null;

lub

DateTime? nullDate;
użytkownik29958
źródło
5

Zawsze ustawiam czas na DateTime.MinValue. W ten sposób nie otrzymuję żadnego wyjątku NullErrorException i mogę porównać go z datą, o której wiem, że nie jest ustawiona.

Patrick Desjardins
źródło
8
Oznacza to, że nie można odróżnić „Naprawdę potrzebuję tutaj DateTime” od „Jest opcjonalny” - Nullable <DateTime> jest znacznie lepszym rozwiązaniem, IMO.
Jon Skeet,
? Naprawdę nie dostaję twojego komentarza. Tak, wiem, kiedy DateTime jest tak daleko od rzeczywistości, to jakby był zerowy ...
Patrick Desjardins,
2
Jest to wygodne, ale widzę DateTime.MinValue jako wartość, a nie specjalny przypadek. Może to tylko prowadzić do problemów w dalszej kolejności. Wybrałbym Nullable <DateTime>.
spoulson
3
Myślę, że coś mi brakuje w mojej odpowiedzi, Spoulson coś napisał, a ja odpowiadałem. O członkach publicznych, cóż, to nie to samo i wiesz o tym. to jest jak String.Empty lub null. Możesz zrobić obie rzeczy, nie dlatego, że String.Empty lepiej jest, gdy null jest zły. Cokolwiek.
Patrick Desjardins,
1
W tej sprawie jestem z Daokiem. To może nie być podejście „książkowe”, ale jest lepsze niż uzyskanie NullReferenceException lub radzenie sobie z nieporęcznym typem dopuszczającym wartość Nullable. Poza tym, ile jest aplikacji, które faktycznie muszą odwoływać się do daty 1 stycznia 1 roku naszej ery?
Jacobs Data Solutions
4

Ostrzegam - gdy używasz wartości Nullable, to oczywiście nie jest on już „czystym” obiektem typu data-godzina, dlatego nie możesz uzyskać bezpośredniego dostępu do elementów DateTime. Spróbuję wyjaśnić.

Używając Nullable <> zasadniczo pakujesz DateTime w pojemnik (dziękuję, generics), który jest zerowalny - oczywiście jego cel. Ten kontener ma własne właściwości, które można wywołać, co zapewni dostęp do wyżej wymienionego obiektu DateTime; po użyciu prawidłowej właściwości - w tym przypadku Nullable.Value - masz dostęp do standardowych elementów DateTime, właściwości itp.

Tak więc - teraz pojawia się kwestia najlepszego sposobu uzyskania dostępu do obiektu DateTime. Jest kilka sposobów, numer 1 jest według FAR najlepszy, a 2 to „stary dlaczego”.

  1. Za pomocą właściwości Nullable.Value

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

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

  2. Konwertowanie obiektu zerowalnego na datetime za pomocą Convert.ToDateTime (),

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

Chociaż odpowiedź jest w tej chwili dobrze udokumentowana, uważam, że użycie Nullable było prawdopodobnie warte opublikowania. Przepraszam, jeśli się nie zgadzasz.

edycja: Usunięto trzecią opcję, ponieważ była nieco zbyt szczegółowa i zależała od wielkości liter.

Gabe
źródło
2

Chociaż wszyscy już udzielili ci odpowiedzi, wymienię sposób, który ułatwia przekazanie daty i godziny do funkcji

[BŁĄD: nie można przekonwertować system.datetime? do system.datetime]

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

Teraz możesz przekazać dte do funkcji bez żadnych problemów.

Bez świąt
źródło
1

Jeśli czasami oczekujesz wartości zerowej, możesz użyć czegoś takiego:

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

W swoim repozytorium użyj zerowej daty i godziny.

public Orders[] GetOrders(string id, DateTime? dateFrom, DateTime? dateTo){...}
DarkoM
źródło
1

Miałem ten sam problem, co musiałem podać Null jako parametr dla DateTime podczas wykonywania testu jednostkowego dla Throw ArgumentNullException. W moim przypadku zadziałało to przy użyciu następującej opcji:

Assert.Throws<ArgumentNullException>(()=>sut.StartingDate = DateTime.Parse(null));
Kiril Dobrev
źródło
0

Biorąc pod uwagę charakter typu danych data / czas, nie może on zawierać nullwartości, tzn. Musi zawierać wartość, nie może być pusty ani niczego. Jeśli zaznaczysz zmienną daty / godziny jako taką, nullablewówczas możesz przypisać do niej wartość zerową. Więc to, co chcesz zrobić, to jedna z dwóch rzeczy (może być więcej, ale mogę myśleć tylko o dwóch):

  • Przypisz minimalną wartość daty / godziny do swojej zmiennej, jeśli nie masz jej wartości. Możesz także przypisać maksymalną wartość daty / godziny - w dowolny sposób, który Ci odpowiada. Upewnij się tylko, że sprawdzasz wartości daty / godziny w całej witrynie. Zdecyduj się na użycie minlub maxi trzymaj się tego.

  • Oznacz zmienną daty / godziny jako nullable. W ten sposób możesz ustawić zmienną daty / godziny na, nulljeśli nie masz do niej zmiennej.

Pokażę pierwszy punkt na przykładzie. Typ DateTimezmiennej nie może być ustawiony na null, potrzebuje wartości, w tym przypadku ustawię ją na DateTimeminimalną wartość, jeśli nie ma żadnej wartości.

Mój scenariusz jest taki, że mam BlogPostzajęcia. Ma wiele różnych pól / właściwości, ale w tym przykładzie wybrałem tylko dwa. DatePublishedjest, gdy post został opublikowany na stronie internetowej i musi zawierać wartość daty / godziny. DateModifiedma miejsce, gdy wpis jest modyfikowany, więc nie musi zawierać wartości, ale może zawierać wartość.

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

     public DateTime DatePublished { get; set; }
}

Użycie ADO.NETdo pobrania danych z bazy danych (przypisanie DateTime.MinValueoznacza brak wartości):

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

Mój drugi punkt możesz osiągnąć, zaznaczając DateModifiedpole jako nullable. Teraz możesz ustawić go, nulljeśli nie ma dla niego żadnej wartości:

public DateTime? DateModified { get; set; }

Przy ADO.NETpobieraniu danych z bazy danych będzie wyglądać nieco inaczej niż powyżej (przypisywanie nullzamiast DateTime.MinValue):

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

Mam nadzieję, że pomoże to wyjaśnić wszelkie nieporozumienia. Biorąc pod uwagę, że moja odpowiedź jest około 8 lat później, prawdopodobnie jesteś już programistą C # :)

Brendan Vogt
źródło