DateTime valor "nulo"

273

Estive pesquisando muito, mas não consegui encontrar uma solução. Como você lida com um DateTime que deve ser capaz de conter um valor não inicializado (equivalente a nulo)? Eu tenho uma classe que pode ter um valor de propriedade DateTime definido ou não. Eu estava pensando em inicializar o proprietário da propriedade para DateTime.MinValue, que poderia ser verificado facilmente. Eu acho que essa é uma pergunta bastante comum, como você faz isso?

Mats
fonte

Respostas:

420

Para DateTimes normais, se você não inicializá-los, eles corresponderão DateTime.MinValue, porque é um tipo de valor e não um tipo de referência.

Você também pode usar um DateTime anulável, assim:

DateTime? MyNullableDate;

Ou a forma mais longa:

Nullable<DateTime> MyNullableDate;

E, finalmente, existe uma maneira integrada de referenciar o padrão de qualquer tipo. Isso retorna nullpara tipos de referência, mas para o nosso exemplo DateTime, ele retornará o mesmo que DateTime.MinValue:

default(DateTime)

ou, nas versões mais recentes do C #,

default
Joel Coehoorn
fonte
8
Seria de grande ajuda se você fornecer um exemplo de como usá-lo. Como você atribui o DateTime no banco de dados, que pode ser DBNull, ao DateTime anulável?
precisa saber é o seguinte
9
Também é bom notar que quando você inicializar eles e com nulo, eles são atribuídos DateTime.MinValuebem
Jeff LaFay
2
@ kirk.burleson que parece uma pergunta separada.
CompuChip 26/07
você precisará MyNullableDate=date; configurá-lo, MyDate = MyNullableDate.Value;lê-lo e if(MyNullableDate.HasValue)verificar se é nulo.
satibel
Para esclarecer um pouco "finalmente" a resposta - o padrão de Nullable <DateTime> (DateTime?) É nulo, porque Nullable <T> cria um tipo de referência.
precisa saber é o seguinte
88

Se você estiver usando o .NET 2.0 (ou posterior), poderá usar o tipo anulável:

DateTime? dt = null;

ou

Nullable<DateTime> dt = null;

depois:

dt = new DateTime();

E você pode verificar o valor com:

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

Ou você pode usá-lo como:

DateTime dt2 = dt ?? DateTime.MinValue;

Você pode ler mais aqui:
http://msdn.microsoft.com/en-us/library/b3h38hb0.aspx

Mark Ingram
fonte
1
Você pode usar tipos anuláveis, mesmo em versões anteriores do .NET, sem necessidade do 3.0.
21138 stephenbayer
1
Ele veio no .NET 2.0, certo? O ? A sintaxe foi adicionada ao VB.NET na versão 3.5, mas está em C # desde a versão 2.0.
David Mohundro 21/10/08
1
Tipos anuláveis ​​estão disponíveis no .Net 2.0. C # teve a abreviação? notação de 2.0. Apenas o VB.Net não tinha a abreviação? na versão 2.0, mas você poderia usar Nullable (Of DateTime)
#
Para o último trecho, eu diria DateTime dt2 = dt ?? DateTime.MinValue;
Joel Coehoorn
Eu usaria dt.GetValueOrDefault()- é a opção mais eficiente.
CompuChip
37

Data hora? MyDateTime {get; set;}

MyDateTime = (dr["f1"] == DBNull.Value) ? (DateTime?)null : ((DateTime)dr["f1"]);
Iman
fonte
1
Isso me ajudou a descobrir que a passagem simplesmente nullnão funciona. Precisa ser (DateTime?)null.
Phractals de Inphinite
33

O caminho a seguir também funciona

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

Observe que a propriedade PublishDate deve ser DateTime?

Aleksei
fonte
12

Eu consideraria o uso de tipos anuláveis .

DateTime? myDateem vez de DateTime myDate.

David Mohundro
fonte
8

Vale ressaltar que, embora uma DateTimevariável não possa ser null, ainda pode ser comparada nullsem um erro do compilador:

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

Você pode usar uma classe anulável.

DateTime? date = new DateTime?();
Aaron Smith
fonte
Provavelmente vale a pena notar que isso fornecerá um comportamento diferente do que instanciar um valor não nulo DateTime. Como mencionado anteriormente, new DateTime()efetivamente lhe dará DateTime.Minenquanto new DateTime?()resultará em nulo.
Vitoc
6

Você pode usar um DateTime anulável para isso.

Nullable<DateTime> myDateTime;

ou a mesma coisa escrita assim:

DateTime? myDateTime;
Patrik Svensson
fonte
6

Você pode definir o DateTime como Nullable. Por padrão, DateTime não é anulável. Você pode torná-lo anulável de duas maneiras. Usando um ponto de interrogação após o tipo DateTime? myTime ou usando o estilo genérico Nullable.

DateTime? nullDate = null;

ou

DateTime? nullDate;
user29958
fonte
5

Eu sempre defino a hora DateTime.MinValue. Dessa forma, não recebo nenhum NullErrorException e posso compará-lo com uma data que sei que não está definida.

Patrick Desjardins
fonte
8
Isso significa que você não pode dizer a diferença entre "Eu realmente preciso de um DateTime aqui" e "É opcional" - Anulável <DateTime> é uma solução muito melhor, IMO.
Jon Skeet
? Eu realmente não entendo o seu comentário. Sim, eu sei quando o DateTime está tão longe brindes da realidade é como se fosse nula ...
Patrick Desjardins
2
É conveniente, mas vejo DateTime.MinValue como um valor, não como uma condição de caso especial. Só pode levar a problemas no final da linha. Eu iria com Nullable <DateTime>.
spoulson 21/10/08
3
Acho que você perdeu algo na minha resposta, Spoulson escreveu algo e eu estava respondendo. Sobre membros públicos, bem, não é o mesmo e você sabe disso. é como String.Empty ou null. Você pode fazer as duas coisas, não porque String.Empty é melhor que null esteja errado. Tanto faz.
Patrick Desjardins
1
Estou com Daok nisso. Pode não ser a abordagem "pelo livro", mas é melhor do que obter uma NullReferenceException ou lidar com o pesado tipo de Nullable. Além disso, quantas aplicações existem por aí que realmente precisam fazer referência à data de 1º de janeiro de 1 dC?
Jacobs Data Solutions
4

Apenas esteja avisado - Ao usar um Nullable, obviamente ele não é mais um objeto de data / hora 'puro'; portanto, você não pode acessar diretamente os membros do DateTime. Vou tentar explicar.

Ao usar Nullable <>, você basicamente envolve o DateTime em um contêiner (obrigado genéricos) cujo valor é anulável - obviamente, seu objetivo. Esse contêiner possui suas próprias propriedades, que você pode chamar, que fornecerão acesso ao objeto DateTime acima mencionado; depois de usar a propriedade correta - neste caso, Nullable.Value - você terá acesso aos membros DateTime, propriedades etc.

Então - agora o problema vem à mente sobre a melhor maneira de acessar o objeto DateTime. Existem algumas maneiras: o número 1 é, de longe, o melhor e 2 é o "cara por que".

  1. Usando a propriedade Nullable.Value,

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

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

  2. Convertendo o objeto anulável em data e hora usando Convert.ToDateTime (),

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

Embora a resposta esteja bem documentada neste momento, acredito que provavelmente valha a pena postar sobre o uso do Nullable. Desculpe se você não concorda.

edit: Removida uma terceira opção, pois era um pouco específica demais e dependia de maiúsculas e minúsculas.

Gabe
fonte
2

Embora todos já tenham lhe dado a resposta, mencionarei uma maneira que facilita a passagem de um datetime para uma função

[ERRO: não é possível converter system.datetime? para system.datetime]

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

Agora você pode passar o dte dentro da função sem problemas.

Sem feriados
fonte
1

Se você está, às vezes, esperando nulo, pode usar algo como isto:

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

No seu repositório, use data e hora que podem ser nulos.

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

Eu tive o mesmo problema que eu tive que fornecer Null como parâmetro para DateTime enquanto realizava o teste de unidade para Throws ArgumentNullException. Funcionou no meu caso usando a seguinte opção:

Assert.Throws<ArgumentNullException>(()=>sut.StartingDate = DateTime.Parse(null));
Kiril Dobrev
fonte
0

Dada a natureza de um tipo de dados de data / hora, ele não pode conter um nullvalor, ou seja, precisa conter um valor, não pode ficar em branco ou conter nada. Se você marcar uma variável de data / hora como nullablesomente então, poderá atribuir um valor nulo a ela. Então, o que você está procurando fazer é uma das duas coisas (pode haver mais, mas só consigo pensar em duas):

  • Atribua um valor mínimo de data / hora à sua variável, se você não tiver um valor para ela. Você também pode atribuir um valor máximo de data / hora - da maneira que mais lhe convier. Apenas verifique se você é consistente em todo o site ao verificar seus valores de data / hora. Decida usar minou maxe ficar com ele.

  • Marque sua variável de data / hora como nullable. Dessa forma, você pode definir sua variável de data / hora como nullse você não tiver uma variável.

Deixe-me demonstrar meu primeiro ponto usando um exemplo. O DateTimetipo de variável não pode ser definido como nulo, ele precisa de um valor; neste caso, eu vou defini-lo como o DateTimevalor mínimo, se não houver valor.

Meu cenário é que eu tenho uma BlogPostaula. Ele tem muitos campos / propriedades diferentes, mas eu escolhi apenas usar dois para este exemplo. DatePublishedé quando a postagem foi publicada no site e precisa conter um valor de data / hora. DateModifiedé quando uma postagem é modificada, para que ela não precise conter um valor, mas pode conter um valor.

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

     public DateTime DatePublished { get; set; }
}

Usando ADO.NETpara obter os dados do banco de dados (atribuir DateTime.MinValuese não há valor):

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

Você pode realizar meu segundo ponto, marcando o DateModifiedcampo como nullable. Agora você pode configurá-lo como nullse não houver valor para ele:

public DateTime? DateModified { get; set; }

Usando ADO.NETpara obter os dados do banco de dados, será um pouco diferente da maneira como foi feito acima (atribuindo em nullvez de DateTime.MinValue):

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

Espero que isso ajude a esclarecer qualquer confusão. Dado que minha resposta é cerca de 8 anos depois, você provavelmente já é um programador C # experiente :)

Brendan Vogt
fonte