Manipulando Datas em Java com o framework Joda Time

Neste artigo vamos conhecer o Joda Time, que é um framework para a manipulação de datas em Java. Como até a versão 7 do Java a API nativa para manipulação de datas era bastante limitada, esse framework é bastante útil.

Calcular a diferença de dias entre duas datas é um problema bastante recorrente em aplicações. Por exemplo, se for criado um filtro com data de início e data de fim, mas a diferença entre as duas datas não pode ser maior que 30 dias, ou as duas datas tem que estar no mesmo mês. Outro exemplo é para quando for necessário saber quantos dias ou horas faltam para um determinado evento.

Até o Java 7, as APIs padrão da plataforma para manipulação de datas não possuíam métodos para a comparação direta de datas. Para fazer isso era necessário converter as datas para long, e com as datas neste formato fazer a comparação. Isso é um problema porque além de ser difícil de implementar, também é difícil de entender o que está acontecendo no código. E essa comparação só vai funcionar para intervalos fixos, como dia e horas, mas para meses e anos que podem ter diferentes intervalos serão ainda mais difíceis de implementar. No Java 8 foi criada uma nova API para facilitar estas tarefas.

Mas em projetos que não podem ser atualizados para a versão mais recente da plataforma, é possível utilizar o framework Joda Time, que é um projeto que tem como objetivo facilitar a manipulação de datas em Java. O Joda Time possui métodos para a comparação, formatação e criação de datas, além de ter diversos métodos para a representação e recuperação de informações sobre datas.

Atualmente o Joda time está na versão 2.5 que foi lançada em outubro de 2013. O framework foi a base para a nova API de datas criadas na versão 8 do Java.

Configuração do Projeto

Para configurar o projeto que utilizará o Joda Time basta incluir o .jar do framework no build-path do projeto. O jar do framework pode ser encontrado no site do projeto Joda Time. Também é possível configurar o projeto com o Maven, e para isso a Listagem 1 mostra como pode ser feito.

<dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.5</version> </dependency>
Listagem 1. Inclusão da dependência do Joda Time no projeto com o Maven

Exemplos de utilização do Joda Time

Para a utilização de datas no JodaTime é utilizada a classe org.joda.time.DateTime, que complementa a classe java.util.Date da plataforma Java. A Listagem 2 mostra como utilizar essa classe e mostra também algumas funcionalidades interessantes da classe. Primeiro mostra como recuperar o nome do mês como String e depois mostra como recuperar qual o dia da semana, também em String da data escolhida. Por fim, mostra como pegar o ano da data criada. Existem diversas outras opções de como pegar os nomes em diferentes línguas e recuperar diversas outras informações sobre a data. A Figura 1 mostra a saída com a execução desses métodos.

DateTime dataFinal = new DateTime(); DateTime dataInicio = new DateTime(2011, 1, 1, 0, 0); System.out.println("Mês ShortString: " + dataFinal.monthOfYear().getAsShortText()); System.out.println("Mês Italiano: " + dataFinal.monthOfYear().getAsShortText(Locale.ITALIAN)); System.out.println("Mês String: " + dataFinal.monthOfYear().getAsText()); System.out.println("Semana do Ano: " + dataFinal.getWeekOfWeekyear()); System.out.println("Dia da semana String: " + dataFinal.dayOfWeek().getAsText()); System.out.println("Dia da semana Francês: " + dataFinal.dayOfWeek().getAsText(Locale.FRENCH)); System.out.println("Dia da semana Italiano: " + dataFinal.dayOfWeek().getAsText(Locale.ITALIAN)); System.out.println("Ano: " + dataFinal.year().get()); System.out.println("Ano no seculo atual:" + dataFinal.yearOfCentury().get());
Listagem 2. Classe DateTime do JodaTime
Figura 1. Execução dos métodos do Joda Time

Outra funcionalidade muito útil do Joda Time é a comparação entre datas. É possível comparar duas datas de diversas maneiras, descobrindo quantos meses, anos, dias, horas, minutos existem entre duas datas. A Listagem 3 mostra um exemplo de como fazer essa comparação. Primeiro é feita a comparação com a classe Days: o método daysBetween compara a quantidade de dias entre uma data inicial e uma data final. O método yearsBetween da classe Years compara os anos de diferença entre duas datas. O método HoursBetween da classe Hours compara as horas de diferença entre as duas datas e o método monthsBetween da classe Month compara os meses de diferença entre as duas datas.

DateTime dataFinal = new DateTime(); DateTime dataInicio = new DateTime(2011, 1, 1, 0, 0); Days d = Days.daysBetween(dataInicio, dataFinal); System.out.println("Diferença dias:" + d.getDays()); Years y = Years.yearsBetween(dataInicio, dataFinal); System.out.println("Diferença anos:" + y.getYears()); Hours h = Hours.hoursBetween(dataInicio, dataFinal); System.out.println("Diferença horas:" +h.getHours()); Months m = Months.monthsBetween(dataInicio, dataFinal); System.out.println("Diferença meses:" + m.getMonths());
Listagem 3. Diversas comparações entre duas datas

A Figura 2 mostra a execução das classes e métodos para a comparação de datas do Joda Time.

Figura 2. Execução dos métodos de comparação de datas do Joda Time

O Joda time também tem uma funcionalidade para descobrir um intervalo e a duração entre duas datas. Para isso são utilizadas as classes org.joda.time.Interval e org.joda.time.Duration. Inicialmente descobrimos o intervalo entre uma data início e uma data fim, que é sempre representado em milissegundos. Com o intervalo criado, podemos criar um objeto do tipo Duration, que tem a duração entre as duas datas e essa duração pode ser recuperada em milissegundos, dias, horas e segundos. A Listagem 4 mostra como isso pode ser feito.

DateTime dataFinal = new DateTime(); DateTime dataInicio = new DateTime(2011, 1, 1, 0, 0); Interval intervalo = new Interval(dataInicio, dataFinal); System.out.println(intervalo); Duration duracao = intervalo.toDuration(); System.out.println("Duração milisegundos:" + duracao.getMillis()); System.out.println("Duração dias:" + duracao.getStandardDays()); System.out.println("Duração horas:" + duracao.getStandardHours()); System.out.println("Duração segundos:" + duracao.getStandardSeconds());
Listagem 4. Intervalo e duração entre duas datas

A Figura 3 mostra a execução do código que cria o intervalo e a duração entre as variáveis dataFinal e DataInicio.

Figura 3. Intervalo e duração entre as variáveis dataInicio e DataFinal

A Listagem 5 mostrar como recuperar o período entre duas datas. A diferença do período e a duração, é que a duração é a comparação total entre as datas e o resultado é retornado em milissegundos. Já o período é a comparação feita campo a campo, onde é comparado dia com dia, mês com mês, e assim por diante. Por exemplo, o período entre as datas 10/10 /2012 e 15/12/2014 é de 5 dias, 2 meses e 2 anos.

DateTime dataFinal = new DateTime(); DateTime dataInicio = new DateTime(2011, 1, 1, 0, 0); Interval intervalo = new Interval(dataInicio, dataFinal); System.out.println(intervalo); Period period = intervalo.toPeriod(); System.out.println("Anos do periodo:" + period.getYears()); System.out.println("Meses do periodo:" + period.getMonths()); System.out.println("Dias do periodo:" + period.getDays()); System.out.println("Horas do periodo:" + period.getHours());
Listagem 5. Período entre duas datas

A Figura 4 mostra a execução do código que cria o período entre as variáveis dataFinal e DataInicio.

Figura 4. Período entre as variáveis dataInicio e DataFinal

Outra funcionalidade do Joda Time é a formatação das datas, isso é bastante parecido com a formatação de datas com a classe SimpleDateFormat da plataforma Java. Para a formatação de datas com o Joda Time são utilizadas as classes org.joda.time.format.DateTimeFormatter e org.joda.time.format.DateTimeFormatter. Como a Listagem 6 mostra, é criado o formatador com padrão que a data deve ser exibida e para utilizar esse formato, o objeto da classe DateTimeFormatter deve ser passado como parâmetro para o método toString das datas.

DateTimeFormatter dtfPadrao = DateTimeFormat.forPattern("dd/MM/yyyy"); System.out.println("Data formatada Padrao: " + dataInicio.toString(dtfPadrao)); System.out.println("Data formatada Padrao: " + dataFinal.toString(dtfPadrao)); DateTimeFormatter dtfExtenso = DateTimeFormat.forPattern("dd 'de' MMMM 'de' yyyy"); System.out.println("Data formatada Extenso: " + dataInicio.toString(dtfExtenso)); System.out.println("Data formatada Extenso: " + dataFinal.toString(dtfExtenso));
Listagem 6. Formatação de datas com o Joda Time

A Figura 5 mostra a execução do código que formata as datas, primeiro com padrão “dd/MM/yyyy” e depois com o padrão “dd ‘de’ MMMM ‘de’ yyyy”.

Figura 5. Formatação das datas com o Joda Time

Como mostra a Listagem 7, é possível fazer operações com as datas no Joda Time como, por exemplo, acrescentar ou remover dias, meses, anos, segundos, entre outros. Uma coisa importante do Joda Time é que assim como a classe String, os objetos do tipo DateTime são imutáveis. Isso quer dizer que, mesmo chamando algum método como, por exemplo, data.plusDays(1), o objeto que executou esse método não será alterado. O método criará outro objeto que terá o objeto inicial como base, mas os dados alterados pelo método executado.

DateTime data = new DateTime(); DateTime dataMaisDias = data.plusDays(100); DateTime dataMaisAno = data.plusWeeks(10); DateTime dataMaisSemanas = data.plusYears(5); DateTime dataMaisHoras = data.plusHours(100); DateTime dataMenosDias = data.minusDays(100); System.out.println(dataMaisDias); System.out.println(dataMaisAno); System.out.println(dataMaisSemanas); System.out.println(dataMaisHoras); System.out.println(dataMenosDias);
Listagem 7. Operações em datas

A Figura 6 mostra a execução do código que realiza as operações nas datas, entre eles a de adicionar dias, meses ou a de remover dias.

Figura 6. Operações em datas no Joda Time

Para mostrar como utilizar o Joda Time, a Listagem 8 mostra alguns exemplos práticos do uso. O primeiro método, chamado horasAnoNovo, recebe uma data e um ano qualquer como parâmetro. Com isso, é calculado quantas horas faltam para se chegar a virada de ano do ano passado como parâmetro para o método. O segundo método, chamado diasAnoNovo, faz a mesma coisa, mas retorna a quantidades de dias que faltam para o ano novo.

O terceiro método, chamado diaSemanaAniversario, recebe como parâmetro uma data qualquer, que representa o aniversário de alguém e retorna uma String com o dia da semana dessa data. O quarto método, chamado intervaloMaiorTrintaDias, compara a diferença de dias entre duas datas: se essa diferença for maior que 30 dias retorna true, caso seja menor retorna false.

public static int horasAnoNovo(DateTime data, int ano) { DateTime dataFinal = new DateTime(ano, 1, 1, 0, 0); return Hours.hoursBetween(data, dataFinal).getHours(); } public static int diasAnoNovo(DateTime data, int ano) { DateTime dataFinal = new DateTime(ano, 1, 1, 0, 0); return Days.daysBetween(data, dataFinal).getDays(); } public static String diaSemanaAniversario(DateTime data) { return data.dayOfWeek().getAsText(); } public static boolean intervaloMaiorTrintaDias(DateTime dataInicial, DateTime dataFinal) { Days dias = Days.daysBetween(dataInicial, dataFinal); if (dias.getDays() > 30) { return true; } return false; }
Listagem 8. Exemplos de uso do Joda Time

A Figura 7 mostra a execução da chamada aos métodos criados: primeiro do método horasAnoNovo com os parâmetros 05/11/2014 e 2030; depois do método diasAnoNovo com os parâmetros 05/11/2014 e 2030; depois do método diaSemanaAniversario com o parâmetro 07/03/2030 e, por último, do método intervaloMaiorTrintaDias om os parâmetros 05/11/2014 e 10/10/2015.

Figura 7. Execução dos métodos de exemplo

Para facilitar a compreensão, a Listagem 9 mostra o código completo do exemplo desenvolvido para esse artigo.

package teste; import java.util.Locale; import org.joda.time.DateTime; import org.joda.time.Days; import org.joda.time.Duration; import org.joda.time.Hours; import org.joda.time.Interval; import org.joda.time.Months; import org.joda.time.Period; import org.joda.time.Years; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; public class Main { public static void main(String[] args) { DateTime dataFinal = new DateTime(); DateTime dataInicio = new DateTime(2011, 1, 1, 0, 0); System.out.println("Mês ShortString: " + dataFinal.monthOfYear().getAsShortText()); System.out.println("Mês Italiano: " + dataFinal.monthOfYear().getAsShortText(Locale.ITALIAN)); System.out.println("Mês String: " + dataFinal.monthOfYear().getAsText()); System.out.println("Semana do Ano: " + dataFinal.getWeekOfWeekyear()); System.out.println("Dia da semana String: " + dataFinal.dayOfWeek().getAsText()); System.out.println("Dia da semana Francês: " + dataFinal.dayOfWeek().getAsText(Locale.FRENCH)); System.out.println("Dia da semana Italiano: " + dataFinal.dayOfWeek().getAsText(Locale.ITALIAN)); System.out.println("Ano: " + dataFinal.year().get()); System.out.println("Ano no seculo atual:" + dataFinal.yearOfCentury().get()); Days d = Days.daysBetween(dataInicio, dataFinal); System.out.println("Diferença dias:" + d.getDays()); Years y = Years.yearsBetween(dataInicio, dataFinal); System.out.println("Diferença anos:" + y.getYears()); Hours h = Hours.hoursBetween(dataInicio, dataFinal); System.out.println("Diferença horas:" +h.getHours()); Months m = Months.monthsBetween(dataInicio, dataFinal); System.out.println("Diferença meses:" + m.getMonths()); Interval intervalo = new Interval(dataInicio, dataFinal); System.out.println(intervalo); Duration duracao = intervalo.toDuration(); System.out.println("Duração milisegundos:" + duracao.getMillis()); System.out.println("Duração dias:" + duracao.getStandardDays()); System.out.println("Duração horas:" + duracao.getStandardHours()); System.out.println("Duração segundos:" + duracao.getStandardSeconds()); Period period = intervalo.toPeriod(); System.out.println("Anos do periodo:" + period.getYears()); System.out.println("Meses do periodo:" + period.getMonths()); System.out.println("Dias do periodo:" + period.getDays()); System.out.println("Horas do periodo:" + period.getHours()); DateTime data = new DateTime(); DateTime dataMaisDias = data.plusDays(100); DateTime dataMaisAno = data.plusWeeks(10); DateTime dataMaisSemanas = data.plusYears(5); DateTime dataMaisHoras = data.plusHours(100); DateTime dataMenosDias = data.minusDays(100); System.out.println(dataMaisDias); System.out.println(dataMaisAno); System.out.println(dataMaisSemanas); System.out.println(dataMaisHoras); System.out.println(dataMenosDias); DateTimeFormatter dtfPadrao = DateTimeFormat .forPattern("dd/MM/yyyy"); System.out.println("Data formatada Padrao: " + dataInicio.toString(dtfPadrao)); System.out.println("Data formatada Padrao: " + dataFinal.toString(dtfPadrao)); DateTimeFormatter dtfExtenso = DateTimeFormat .forPattern("dd 'de' MMMM 'de' yyyy"); System.out.println("Data formatada Extenso: " + dataInicio.toString(dtfExtenso)); System.out.println("Data formatada Extenso: " + dataFinal.toString(dtfExtenso)); System.out.println("Horas que faltam ano novo: " + horasAnoNovo(new DateTime(), 2030)); System.out.println("Dias que faltam ano novo: " + diasAnoNovo(new DateTime(), 2030)); System.out.println("O seu aniversário cai em uma: " + diaSemanaAniversario(new DateTime(2030, 3, 7, 0, 0))); System.out.println("O intervalo tem mais que 30 dias?" + intervaloMaiorTrintaDias(dataInicio, dataFinal)); } public static int horasAnoNovo(DateTime data, int ano) { DateTime dataFinal = new DateTime(ano, 1, 1, 0, 0); return Hours.hoursBetween(data, dataFinal).getHours(); } public static int diasAnoNovo(DateTime data, int ano) { DateTime dataFinal = new DateTime(ano, 1, 1, 0, 0); return Days.daysBetween(data, dataFinal).getDays(); } public static String diaSemanaAniversario(DateTime data) { return data.dayOfWeek().getAsText(); } public static boolean intervaloMaiorTrintaDias(DateTime dataInicial, DateTime dataFinal) { Days dias = Days.daysBetween(dataInicial, dataFinal); if (dias.getDays() > 30) { return true; } return false; } package teste; }
Listagem 9. Código completo do exemplo desenvolvido no artigo

A Figura 8 mostra a saída da execução completa do código criado para o exemplo. A aplicação foi desenvolvida como uma aplicação simples de console, mas o Joda Time pode ser utilizado em qualquer tipo de projeto Java, como um projeto Web ou um projeto EJB.

Figura 8. Saída da execução da aplicação inteira

O Joda Time é um framework para a manipulação de datas em Java, como até a versão 7 do Java a API nativa para manipulação de datas era bastante limitada, esse framework é bastante útil.

No Java 8, foi implementada uma nova API de datas, que foi totalmente baseada no Joda Time. Em projetos que já utilizam o Java 8, talvez o Joda Time não seja necessário, mas ainda existem muitos projetos que não podem ser atualizados para a versão mais nova do Java, nesses projetos, o Joda Time ainda pode ser bastante útil.

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados