NET 6 -  Usando apenas Data (DateOnly)


Hoje veremos o novo recurso DateOnly e TimeOnly do .NET 6 na linguagem C#.

Quantas vezes você quis apenas armazenar uma data, como uma data de aniversário, ou apenas as horas de um evento e teve que usar o tipo DateTime, onde era obrigado definir a data e a hora ?

Embora isso funcionasse, muitas vezes a parte do tempo atrapalhava ao comparar datas ou quando queríamos manipular uma data sem realmente se preocupar com a hora.

E era estranho quando se trabalhava com um banco de dados SQL que tem um tipo “data” (sem hora), mas ao carregar os dados em C#, você tinha que lidar com um DateTime que carregava a data e hora.

Pensando em facilitar o tratamento de data e horas o .NET 6 disponibiliza dois novos tipos : DateOnly e TimeOnly que permitem que os desenvolvedores representem apenas data ou apenas hora de um DateTime.

Esses dois novos tipos são structs ou estruturas (tipos de valor) e podem ser usados quando seu código lida com conceitos de data ou hora de forma independente.

Ambos os tipos podem ser encontrados no namespace System.  (Esses dois tipos se alinham bem com os tipos de dados de data e hora do SQL Server.)

Usando DateOnly no .NET 6

Podemos usar DateOnly quando precisamos representar uma data sem um componente de hora como a data de nascimento ou data de vencimento de uma fatura. 

Nesses casos, raramente precisamos utilizar a parte da hora de um DateTime, e uma solução padrão seria definir a hora como 00: 00: 00.000. Com DateOnly, podemos ser mais explícitos sobre nossa intenção.

Podemos construir uma instância em DateOnly, passando o ano, mês e dia (todos do tipo int) como argumentos:

using System;

var dataAniversario = new DateOnly(2021, 09, 13);
 

Este código cria um DateOnly representando 13 de setembro de 2021.

Internamente a struct DateOnly usa um numero inteiro para rastrear um número de dia com um intervalo válido de 0 mapeado para primeiro de janeiro de 0001 até 3.652.058 mapeado para 31 de dezembro de 9999.

E se você tiver um DateTime já existente e quiser criar uma instância de DateOnly a partir dele ?

Para isso podemos usar o método FromDateTime:

using System;

var dataAtual = DateOnly.FromDateTime(DateTime.Now);
 

Podemos também fazer um parse de uma string exibindo uma data em uma representação DateOnly usando o método Parse que pode lançar uma exceção ou TryParse que retorna um bool indicando sucesso ou falha.

using System;

if (DateOnly.
TryParse("1979/08/12",
     new CultureInfo("pt-Br"),
     DateTimeStyles.None, out var resultado))
{
       Console.WriteLine(resultado);
}
 

Neste código tentamos analisar uma data a partir do primeiro argumento, a representação string da data.

Como a análise da data pode ser afetada pela cultura, neste exemplo definimos explicitamente o uso da cultura pt-BR, e assim analisar a data no formato desta cultura que é o formato  dd/MM/yyyy.

Neste exemplo, a cultura atual da thread em execução é usada para determinar o formato usado. Como meu sistema esta sendo executado usando a cultura pt-BR o formato da data exibido será :   12/08/1979

Podemos também adicionar dias, meses ou anos a uma instância DateOnly, o que vai resultar em uma nova instância com a data ajustada:

var data = new DateOnly(2021, 09, 14);
Console.WriteLine($"Incluindo 1 dia, 1 mês e 1 ano a {data.ToString()}\n");
var novaData = data.AddDays(1).AddMonths(1).AddYears(1);

Console.WriteLine(novaData);

 

O resultado vai exibir : 15/10/2022

A seguir temos o código completo definido em uma aplicação Console no NET 6.0:

using System;
using System.Globalization;
Console.WriteLine("NET 6 - Usando DateOnly\n");
var dataAniversario = new DateOnly(2020, 09, 13);
Console.WriteLine(dataAniversario);
Console.WriteLine("NET 6 - Obtendo um DateOnly a partir de um DateTime\n");
var dataAtual = DateOnly.FromDateTime(DateTime.Now);
Console.WriteLine(dataAtual);
Console.WriteLine("Fazendo um parse usando a cultura atual\n");
if (DateOnly.TryParse("1979/08/12", 
    new CultureInfo("pt-BR"), 
    DateTimeStyles.None, out var resultado))
{
    Console.WriteLine(resultado);
}
Console.WriteLine("NET 6 - Adicionando dias, meses e anos a um DateOnly\n");
var data = new DateOnly(2021, 09, 14);
Console.WriteLine($"Incluindo 1 dia, 1 mês e 1 ano a {data.ToString()}\n");
var novaData = data.AddDays(1).AddMonths(1).AddYears(1);
Console.WriteLine(novaData);
Console.ReadKey();

Abaixo temos o resultado obtido:

Podemos fazer o tratamento das datas definidas como um struct DateOnly usando as propriedades Year, Month, Day e DayOfWeek :

using System;
using System.Globalization;
Console.WriteLine("NET 6 - Manipulando datas com DateOnly\n");
DateOnly data = new DateOnly(2021, 9, 15);
Console.WriteLine(data.Year);               // 2021
Console.WriteLine(data.Month);            // 9
Console.WriteLine(data.Day);                // 15
Console.WriteLine(data.DayOfWeek);    // Wednesday

A propriedade DayNumber permite calcular o número de dias entre duas datas. No exemplo a seguir podemos usar este recurso para calcular o número de dias entre a data do nascimento e a data atual e depois dividir por 365 e assim obter a idade aproximada de uma pessoa:

Console.WriteLine("NET 6 - Usando DateOnly\n");
Console.WriteLine("Informe a data de nascimento");
Console.WriteLine("Informe o dia (dd) : ");
var dia = Convert.ToInt16(Console.ReadLine());
Console.WriteLine("Informe o mês (mm) : ");
var mes = Convert.ToInt16(Console.ReadLine());
Console.WriteLine("Informe o ano (aaaa) : ");
var ano = Convert.ToInt16(Console.ReadLine());
var dataAniversario = new DateOnly(ano, mes, dia);
Console.WriteLine($"Você nasceu em : {dataAniversario}");
var dataAtual = DateOnly.FromDateTime(DateTime.Now);
var numeroDias = dataAtual.DayNumber - dataAniversario.DayNumber;
Console.WriteLine($"Parabéns você já viveu {numeroDias} dias");
var idade = (numeroDias / 365);
Console.WriteLine($"Sua idade aproximada é {idade} anos");
Console.ReadKey();

 

O resultado obtido é o seguinte:

Pegue o projeto aqui :   Net6_DateOnly.zip (sem as referências. Precisa do NET 6)

Na próxima parte do artigo vou apresentar o novo recurso TimeOnly do NET 6.

"Disse-lhe Jesus: Porque me viste, Tomé, creste; bem-aventurados os que não viram e creram."
João 20:29

Referências:


José Carlos Macoratti