Clique aqui para ler todos os artigos desta edição
Manipulando Datas e Horas com C# e VB .NET
por Marden Menezes
Manipulação de datas e horas em aplicações é um processo bastante comum e que se faz presente em variados tipos de softwares, desde simples cadastros até os complexos sistemas de gerenciamento de datas e períodos de tempo. Nesse artigo mostrarei como manipular datas em .NET, as maneiras de formatação, cálculo e globalização de suas informações de tempo.
A classe DateTime
A principal classe para manipulação de datas em .NET é a DateTime do namespace System, que conta o tempo através de ticks (cada tick representa 100 nano segundos) desde 01/01/0001 até 31/12/9999. A classe DateTime possui diversos métodos e propriedades estáticas que nos permitem manipular data e hora sem precisar criar instâncias de DateTime. Veja a Tabela 1.
Método/Propriedade |
Descrição |
DateTime.MinValue |
Representa o valor mínimo, 01/01/0001 00:00:00. |
DateTime.MaxValue |
Representa o valor máximo, 31/12/9999 23:59:59 |
DateTime.Now |
Retorna um objeto DateTime que representa a data e hora atual no computador |
DateTime.Today |
Retorna apenas a data atual no computador |
DateTime.IsLeapYear(int ano) |
Retorna um valor booleano indicando se o ano passado como parâmetro em formato de 4 dígitos é bissexto. |
DateTime.Compare(DateTime d1, DateTime d2) |
Método que retorna 0 se as duas datas forem iguais, 1 se d1 for maior e -1 se d2 for maior |
DateTime.DayInMonth(int ano, int mes) |
Retorna a quantidade de dias no mês do ano especificado. |
Tabela 1. Alguns métodos e propriedades de System.DateTime
Além dos métodos e propriedade estáticas, há a possibilidade de criar objetos DateTime e manipulá-los utilizando seus métodos e propriedades. A Tabela 2 mostra alguns deles.
Método/Propriedade |
Descrição |
|
Date |
Retorna a data representada nessa instância do objeto | |
TimeOfDay |
Retorna o horário guardado nessa instância do objeto | |
AddHours(double valor) |
Adiciona horas ao horário guardado no objeto. Há também métodos AddMinutes(), AddSeconds(), AddMiliSeconds() usando a mesma idéia. | |
AddDays(double valor) |
Adiciona dias à data guardada no objeto. Há também métodos AddMonths(), AddYears() seguindo a mesma idéia. |
Tabela 2. Alguns métodos e propriedades de um objeto criado do tipo DateTime
A Listagem 1 demonstra a criação de objetos DateTime e a utilização de alguns dos métodos e propriedades.
Listagem 1. Criação e utilização de objetos DateTime em C# e VB .NET
//código em C#
//cria um objeto DateTime representando o dia 23/12/2020, com horário 00:00:00
DateTime data = new DateTime(2020,12,23);
//cria outro objeto que representa a data e hora atual
DateTime dataAtual = DateTime.Now;
//se a data atual for anterior a 23/12/2020, imprima “Data anterior”
if (DateTime.Compare(dataAtual,data) == -1)
{
Console.WriteLine(“Data anterior”);
}
//soma 50 anos a data atual:
dataAtual = dataAtual.AddYears(50);
//compara se a data atual é posterior a 23/12/2020:
if (DateTime.Compare(dataAtual,data) == 1)
{
Console.WriteLine(“Data posterior”);
}
‘código em VB .NET
‘cria um objeto DateTime representando o dia 23/12/2020, com horário 00:00:00
Dim data As New DateTime(2020,12,23)
‘cria outro objeto que representa a data e hora atual
Dim dataAtual As DateTime = DateTime.Now
‘se a data atual for anterior a 23/12/2020, imprima “Data anterior”
If (DateTime.Compare(dataAtual,data) = -1) Then
Console.WriteLine(“Data anterior”)
End If
‘soma 50 anos a data atual:
dataAtual = dataAtual.AddYears(50)
‘compara se a data atual é posterior a 23/12/2020:
If (DateTime.Compare(dataAtual,data) = 1) Then
Console.WriteLine(“Data posterior”)
End If
Note que o método AddYears() (assim como qualquer outro método de adição em datas ou horas) não adiciona anos ao objeto que o está chamando diretamente. Ele adiciona o valor passado como argumento a uma cópia do objeto que o chama, retornando essa cópia após realizar a soma dos anos. Isso significa que é necessário atribuir o valor de retorno do método a algum objeto. Veja um exemplo na Listagem 2.
Listagem 2. Utilização de AddYears() em C# e VB .NET
//código em C#
//não realiza nenhuma mudança no objeto dataAtual:
dataAtual.AddMonth(4);
//cria uma cópia do objeto dataAtual, modifica adicionando meses e retorna a cópia modificada
dataAtual = dataAtual.AddMonth(4);
‘código em VB .NET
‘não realiza nenhuma mudança no objeto dataAtual:
dataAtual.AddMonth(4)
‘cria uma cópia do objeto dataAtual, modifica adicionando meses e retorna a cópia modificada
dataAtual = dataAtual.AddMonth(4)
Formatando datas
Algo tão importante quanto saber trabalhar com datas é saber formatá-las para que sejam mostradas ao usuário final. Os projetistas do Visual Basic .NET trouxeram soluções quer permitem transformar a formatação de datas em algo extremamente trivial. O namespace Microsoft.VisualBasic nos traz o método FormatDateTime() que recebe uma expressão do tipo Date e um formato representado pela enumeração DateFormat. Você verá que Date é apenas uma forma de transformar o uso da classe DateTime mais fácil para os programadores que vieram do Visual Basic 6.0. Date é apenas um “alias” para DateTime, possuindo os mesmos métodos e propriedades, nos permitindo escolher qual das duas classes iremos usar sem nenhuma perda no nosso código. A Tabela 3 mostra os tipos de formato que podemos usar.
Formato |
Descrição |
DateFormat.GeneralDate |
Mostra a data e a hora. As configurações de data e hora são determinadas pelas configurações regionais do computador. |
DateFormat.LongDate |
Mostra apenas a data usando a configuração de data completa determinada pelas configurações regionais do computador. |
DateFormat.ShortDate |
Mostra apenas a data usando a configuração de data abreviada determinada pelas configurações regionais do computador. |
DateFormat.LongTime |
Mostra apenas a hora usando a configuração de hora completa determinada pelas configurações regionais do computador. |
DateFormat.ShortTime |
Mostra apenas a data usando a configuração de hora abreviada determinada pelas configurações regionais do computador. |
Tabela 3. Formatos da enumeração DateFormat em VB .NET
A Listagem 3 mostra os diversos formatos a serem usados para exibir datas ao usuário utilizando o FormatDateTime() e a enumeração DateFormat de VB.NET. A execução do código é mostrada na Figura 1.
Listagem 3. Formatando datas em VB .NET com DateFormat
‘código em VB .NET
Sub Main()
‘cria um objeto DateTime representando a data 23/12/1982 as 13:00:40:00
‘é possível também usar Date ao invés de DateTime
Dim data As New DateTime(1982,12,23,13,0,40,0)
‘formata a data em vários formatos
Console.WriteLine(“Usando o formato GeneralDate: ” & FormatDateTime(data,DateFormat.GeneralDate))
Console.WriteLine(“Data em formato LongDate: ”& FormatDateTime(data,DateFormat.LongDate))
Console.WriteLine(“Data em formato ShortDate: ”& FormatDateTime(data,DateFormat.ShortDate))
Console.WriteLine(“Hora em formato LongTime: ”& FormatDateTime(data,DateFormat.LongTime))
Console.WriteLine(“Hora em formato ShortTime: ”& FormatDateTime(data,DateFormat.ShortTime))
End Sub
Figura 1. Execução do código da Listagem 3
O método FormatDateTime() também permite a utilização de formatos personalizados para datas, possibilitando que escolhamos o formato que melhor se adeque as necessidades. Veja na Listagem 4 as possiblidades de personalizar datas com o método FormatDateTime().
Listagem 4. Personalizando a formatação das datas
‘código em VB .NET
Sub Main()
‘cria a data do tipo DateTime (lembrando que criar usando Date obtém o mesmo resultado em VB .NET )
Dim data As New DateTime(1982,12,23,13,0,40)
’DIAS
Console.WriteLine("<--Personalizando formatos dos dias-->")
Console.WriteLine("d: -> " & Format(data, "d"))
Console.WriteLine("dd: -> " & Format(data, "dd"))
Console.WriteLine("ddd: -> " & Format(data, "ddd"))
Console.WriteLine("dddd: -> " & Format(data, "dddd"))
’MESES
Console.WriteLine("<--Personalizando formatos dos meses-->")
Console.WriteLine("M: -> " & Format(data, "M"))
Console.WriteLine("MM: -> " & Format(data, "MM"))
Console.WriteLine("MMM: -> " & Format(data, "MMM"))
Console.WriteLine("MMMM: -> " & Format(data, "MMMM"))
’ANOS
Console.WriteLine("<--Personalizando formatos dos anos-->")
Console.WriteLine("y: -> " & Format(data, "y"))
Console.WriteLine("yy: -> " & Format(data, "yy"))
Console.WriteLine("yyyy -> " & Format(data, "yyyy"))
’HORAS
Console.WriteLine("<--Personalizando formatos de horas -->")
Console.WriteLine("hh: -> " & Format(data, "hh"))
Console.WriteLine("HH: -> " & Format(data, "HH"))
’MINUTOS
Console.WriteLine("<--Personalizando formatos dos minutos-->")
Console.WriteLine("mm: -> " & Format(data, "mm"))
’SEGUNDOS
Console.WriteLine("<--Personalizando formatos dos segundos-->")
Console.WriteLine("ss: -> " & Format(data, "ss"))
’FORMATOS ALEATÓRIOS, PERSONALIZADOS PELO DESENVOLVEDOR
Console.WriteLine("<--formatos criados pelo desenvolvedor -->")
Console.WriteLine("dd/MM/yyyy: -> " & Format(data, "dd/MM/yyyy"))
Console.WriteLine("MM/dd/yyyy: -> " & Format(data, "MM/dd/yyyy"))
Console.WriteLine("dd/MM: -> " & Format(data, "dd/MM"))
Console.WriteLine("dd ddd/MMM/yyyy: -> " & Format(data, "dd ddd/MMM/yyyy"))
Console.WriteLine("dd dddd/MMM/yyyy: -> " & Format(data, "dd dddd/MMM/yyyy"))
Console.WriteLine("dddd dd/MMM/yyyy: -> " & Format(data, "dddd dd/MMM/yyyy"))
End Sub
A execução do código da Listagem 4 é mostrada na Figura 2.
Figura 2. Execução do código da listagem 4
Globalização
Em certas situações precisamos trabalhar com calendários diferentes do calendário gregoriano tradicional. O namespace System.Globalization permite trabalhar com diferentes tipos de calendários dependendo da aplicação. Veja na Tabela 4 as classes e os respectivos calendários o qual cada classe se relaciona. Todas as classes herdam de System.Globalization.Calendar.
Classe |
Tipo do Calendário |
GregorianCalendar |
Calendário Gregoriano, o padrão no mundo ocidental. Possui várias versões de calendário, que pode ser definida pela enumeração GregorianCalendarTypes. O padrão é Localized, que utiliza a versão referente a localização setada no CultureInfo da aplicação. Apesar do calendário gregoriano possuir duas eras, B.C. (Before Christ) e A.C. (After Christ), só a era AC está implementada. |
HebrewCalendar |
Representa o calendário Hebreu. Esta implementação só reconhece do ano 5343 a 6000 (equivalente ao intervalo de 1582 a 2240 AC no calendário gregoriano). |
HijriCalendar |
O calendário Hijri contém apenas uma era, A.H. ("Anno Hegirae", que significa “o ano da migração”). A data 01 de janeiro de 2001 A.C. no calendário gregoriano representa o sexto dia do mês de Shawwal no ano de 1421 A.H. no calendário Hijri. |
JapaneseCalendar |
O calendário Japonês trabalha exatamente como o gregoriano, mas possui diversas eras que mudam a cada mudança de imperador. A era atual é a era Heisei, que começou no ano 1989 do calendário gregoriano. |
JulianCalendar |
O predecessor do calendário Gregoriano foi criado por Júlio César em 45 B.C. É igual ao calendário Gregoriano em sua essência, diferindo apenas a data inicial e a forma de calcular anos bissextos. A data 01 de janeiro de 2001 A.C. no calendário gregoriano equivale a 19 de dezembro de 2000 no calendário Juliano. |
KoreanCalendar |
Também é semelhante ao calendário Gregoriano possuindo apenas ano inicial e era diferentes. Apenas a era atual está implementada e a data de 01 de janeiro de 2001 representa 01 de janeiro de 4334 da atual era do calendário Coreano. |
TaiwanCalendar |
Assim como o Coreano, é semelhante ao calendário gregoriano, moficando apenas o ano e a era. A data de 01 de janeiro de 2001 representa 01 de janeiro de 90 da atual era do calendário de Taiwan. |
Tabela 4. Calendários disponíveis no namespace System.Globalization
O construtor da classe System.DateTime permite que criemos datas em diferentes calendários passando como argumento um objeto do tipo Calendar. Para convertermos uma data que está em um calendário para outro usamos os métodos específicos de cada calendário que recebem uma data em um determinado calendário e retornam o dia, o mês e o ano em outro calendário. A Listagem 5 exemplifica maneiras de trabalhar com conversão entre diferentes calendários.
Listagem 5. Conversão entre calendários em C# e VB .NET
//código em C#
//cria um objeto DateTime no calendário Gregoriano padrão representando a data 01/01/2001
DateTime gregoriano = new DateTime(2001,1,1);
//converte a data para o calendário Hebreu
//cria um objeto do tipo HebrewCalendar
HebrewCalendar calHebreu = new HebrewCalendar();
//transforma dia, mês e ano
int dia = calHebreu.GetDayOfMonth(gregoriano);
int mes = calHebreu.GetMonth(gregoriano);
int ano = calHebreu.GetYear(gregoriano);
Console.WriteLine(“Data no calendário hebreu: “ + dia + “/” + mes + “/” + ano);
//cria o objeto DateTime no calendário Hebreu
DateTime hebreu = new DateTime(ano,mes,dia,new HebrewCalendar());
//converte a data para o calendário Coreano
//cria um objeto do tipo KoreanCalendar
KoreanCalendar calCoreano = new KoreanCalendar ();
//transforma dia, mês e ano
dia = calCoreano.GetDayOfMonth(hebreu);
mes = calCoreano.GetMonth(hebreu);
ano = calCoreano.GetYear(hebreu);
Console.WriteLine(“Data no calendário coreano: “ + dia + “/” + mes + “/” + ano);
‘Código em VB .NET
‘cria um objeto DateTime no calendário Gregoriano padrão representando a data 01/01/2001
Dim gregoriano As DateTime = New DateTime(2001,1,1)
‘converte a data para o calendário Hebreu
‘cria um objeto do tipo HebrewCalendar
Dim calHebreu As HebrewCalendar = New HebrewCalendar()
‘transforma dia, mês e ano
Dim dia As Integer = calHebreu.GetDayOfMonth(gregoriano)
Dim mes As Integer = calHebreu.GetMonth(gregoriano)
Dim ano As Integer = calHebreu.GetYear(gregoriano)
Console.WriteLine(“Data no calendário hebreu: “ & dia & “/” & mes & “/” & ano)
‘cria o objeto DateTime no calendário Hebreu
Dim hebreu As New DateTime(ano,mes,dia,new HebrewCalendar())
‘converte a data para o calendário Coreano
‘cria um objeto do tipo KoreanCalendar
Dim calCoreano As New KoreanCalendar()
‘transforma dia, mês e ano
dia = calCoreano.GetDayOfMonth(hebreu)
mes = calCoreano.GetMonth(hebreu)
ano = calCoreano.GetYear(hebreu)
Console.WriteLine(“Data no calendário coreano: “ + dia + “/” + mes + “/” + ano)
Lembre-se que ao converter datas você estará trabalhando com diferentes calendários e que temos intervalos fixos implementados para cada calendário. Pode acontecer de uma data em um calendário específico possa estar fora do intervalo implementado para outro calendário. Isso causará uma exceção e você deverá estar apto a tratá-la ou a testar se a data está no intervalo válido antes de fazer a conversão.
Convertendo de objetos para datas
Uma preocupação constante é a forma de converter strings que representam datas (que foram, por exemplo, digitadas pelo usuário do sistema na interface gráfica) para objetos que representam datas. O .NET traz a classe System.Convert como uma solução para conversões de tipos. No caso de datas, a classe System.Convert nos traz o método ToDateTime() que pode transformar outros tipos de objetos em um DateTime.
Outra forma de conversão para datas é o CDate e o CType, métodos exclusivos de Visual Basic .NET. O resultado, na prática, é o mesmo da classe System.Convert, mas permite aos usuários de VB 6 usarem sintaxe parecida com o da linguagem a qual estão acostumados. Outro “açúcar sintático” criado para os desenvolvedores de Visual Basic .NET é a possibilidade do uso do tipo Date ao invés do DateTime. Na prática nada muda, o Date é apenas um “alias” para a classe DateTime, possuindo os mesmos métodos e propriedades da mesma.
Veja na Listagem 6 um código que recebe uma string do teclado, transforma em uma data, soma 21 dias a essa data e retorna a resposta ao usuário, que na verdade representa a data passada 3 semanas depois. Perceba que caso a conversão para uma data gere uma exception o método Convert.ToDateTime() gera a exception FormatException, diferentemente do CDate, que gera o InvalidCastException. É importante tratar os erros para evitar paradas inesperadas no fluxo de execução do programa.
Listagem 6. Conversão de string para data em C# e VB .NET
//código em C#
try {
//recebe uma string do teclado e armazena em um objeto do tipo string
string dataRecebida = Console.ReadLine();
//converte para um objeto DateTime
DateTime dataConvertida = Convert.ToDateTime(dataRecebida);
//soma 21 dias e retorna o resultado ao objeto
dataConvertida = dataConvertida.AddDays(21);
//imprime na tela o resultado
Console.WriteLine(“A data “ + dataConvertida + “ representa 3 semanas depois da data digitada”);
}
//caso a conversão não tenha sido bem sucedida
catch (FormatException ex) {
Console.WriteLine(“O valor digitado não pode ser convertido para uma data”);
}
‘código em VB .NET usando System.Convert e System.DateTime
Try
‘recebe uma string do teclado e armazena em um objeto do tipo string
Dim dataRecebida As String = Console.ReadLine()
‘converte para um objeto DateTime
Dim dataConvertida As DateTime = Convert.ToDateTime(dataRecebida)
‘soma 21 dias e retorna o resultado ao objeto
dataConvertida = dataConvertida.AddDays(21)
‘imprime na tela o resultado
Console.WriteLine(“A data “ & dataConvertida & “ representa 3 semanas depois da data digitada”)
‘caso a conversão não tenha sido bem sucedida
Catch ex As FormatException
Console.WriteLine(“O valor digitado não pode ser convertido para uma data”)
End Try
‘código em VB .NET usando CDate e Date
Try
‘recebe uma string do teclado e armazena em um objeto do tipo string
Dim dataRecebida As String = Console.ReadLine()
‘converte para um objeto Date
Dim dataConvertida As Date = CDate(dataRecebida)
‘soma 21 dias e retorna o resultado ao objeto
dataConvertida = dataConvertida.AddDays(21)
‘imprime na tela o resultado
Console.WriteLine(“A data “ & dataConvertida & “ representa 3 semanas depois da data digitada”)
‘A exception levantada é diferente do Convert.ToDateTime()
Catch ex As InvalidCastException
Console.WriteLine(“O valor digitado não pode ser convertido para uma data”)
End Try
Conclusão
Vimos nesse artigo como é fácil criar, modificar e formatar datas na plataforma .NET, inclusive trabalhando com diversos calendários, desde o calendário Gregoriano usado no mundo ocidental até o extinto calendário Juliano, criado na época de Júlio César. Mostramos também técnicas de formatação de datas em Visual Basic .NET, que nos traz o método FormatDateTime(), aumentando a produtividade na hora de trabalhar com datas e mostrá-las ao usuário final do sistema.
Download disponível em http://www.neoficio.com.br/msdn
Referências:
Os seguintes artigos foram utilizados como referências e podem ajudá-lo a descobrir ainda mais sobre manipulação de datas em .NET:
Renato Haddad (http://www.msdnbrasil.com.br/tecnologias/visualbasic_hora.aspx)
José Carlos Macoratti (http://www.macoratti.net/vbn_data.htm)
Dan Rogers, da MSDN (http://msdn.microsoft.com/netframework/default.aspx?pull=/library/en-us/dndotnet/html/datetimecode.asp)