Fala pessoal!
Esse post é para você que nem conseguiu assimilar as novidades do Java 7 ainda! Sim, porque o Java 8 está logo ali. 😀
Depois de um atraso até bem justificado, o lançamento da versão final do JDK 8 ficou para março/2014, o que já está bem próximo.
Nenhuma outra versão da plataforma Java teve tantas novidades como essa, a 8. A última grande novidade foi a introdução de generics no Java 5, e isso foi em 2004! No meio de todas essas novidades, a que vou falar aqui é uma também muito aguardada.
A JSR 310 foi aprovada pelo comitê executivo em 2007. Há 6 anos! E está esperando um lugar ao sol desde então. Finalmente foi incorporada ao Java 8 e quem quiser brincar antes do lançamento oficial é só baixar uma early access release do JDK 8 no site do Open JDK
A opinião de todos com relação a API atual para manipulação de datas do Java SE é unânime: Ruim demais. A JSR 310, baseada em grande parte no framework JODA-TIME, veio para tentar resgatar nossa dignidade 🙂
Overview
As classes da JSR 310 encontram-se no pacote ‘java.time.*’. Abaixo segue uma breve descrição das principais e em qual cenário cada uma delas deve ser usada:
Classe | Descrição |
---|---|
LocalDate | Representa uma data simples, sem nenhuma referência a tempo/hora. Ideal para representar eventos onde a hora não é importante: Aniversários, Feriados, etc. |
LocalDateTime | Uma data completa com data e hora/timezone. Ideal para representar eventos onde a data e também a hora são importantes: Reuniões, compromissos, etc. |
LocalTime | Representação somente de hora. Nessa classe não há qualquer informação de data, por isso deve ser usada nas ocasiões onde somehte a hora do dia é importante. |
Period | Uma representação de quantidade de tempo, usando as unidades dia, mes e ano. Essa vai ser a classe usada para calcular por exemplo a quantidade de tempo entre duas datas, mas sempre usando as unidades mencionadas acima. Exemplo: Faltam 7 meses e 22 dias para a Copa do Mundo. |
Duration | Oferece uma maneira mais precisa de determinar quantidade de tempo, em segundo e nano segundos. É bem parecida com a classe Period, mas vai ser usada em casos onde se faz necessário uma exatidão mais precisa do tempo. |
DateTimeFormatter | Formatador de objetos date. Vai ser utilizado para formatar objetos LocalDate/LocalDateTime para String e vice-versa. |
Exemplos
Algo interessante a ser observado é que todas as classes adotam uma convenção de static factory methods que começam com o prefixo of para construção de objetos. E também como todos os objetos são imutáveis, o padrão Builder é usado extensivamente. O trecho abaixo demonstra como instanciar alguns dos objetos citados na tabela acima:
import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; // ... //criar datas LocalDate dataAtual = LocalDate.now(); //data atual LocalDate data1 = LocalDate.of(2014, 3, 22); //22-mar-2014 LocalDate data2 = LocalDate.of(2014, Month.MARCH, 22); //22-mar-2014 LocalDate data3 = Year.of(2010).atMonth(12).atDay(24); //24-dez-2010 //criar objeto com data e hora LocalDateTime dateTimeAtual = LocalDateTime.now(); LocalDateTime dateTime1 = LocalDateTime.of(2013, Month.MARCH, 21, 21, 10, 1); //21-mar-2013 as 21h10m1s
Alguns casos mais comuns, para transformar String’s em datas e vice-versa:
import java.time.LocalDate; import java.time.format.DateTimeFormatter; // ... //criação de um DateTimeFormatter com o padrao dd/MM/yyyy (dia/mes/ano) DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); //criar um objeto LocalDatel a partir da String "15/11/2013" String s = "15/11/2013"; LocalDate data = LocalDate.parse(s, formatter); System.out.println(data); //pegar a data atual e transformar em String usando o mesmo formatter LocalDate dataAtual = LocalDate.now(); String dataAtualString = dataAtual.format(formatter); System.out.println(dataAtualString);
Se você quer forçar que uma data seja validada, é só usar o enum ResolverStyle.STRICT.
//Criar um fomatter do tipo "STRICT" DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy"); formatter = formatter.withResolverStyle(ResolverStyle.STRICT); String s = "31/02/2013"; //31 de fevereiro LocalDate data = LocalDate.parse(s, formatter); //exception!
Agora, vamos supor que você queira saber quanto tempo falta para o reveillon. Observe que a classe Period representa o tempo em unidades determinadas: dias, meses e anos. Entretanto também é possível recuperar somente a diferença em dias:
import java.time.LocalDate; import java.time.Month; import java.time.Period; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; //... LocalDate dataInicial = LocalDate.of(2013, Month.NOVEMBER, 15); //data inicial: 15-nov-2013 LocalDate dataFinal = LocalDate.of(2013, Month.DECEMBER, 31); //data final: 31-dez-2013 //Recuperar o periodo completo entre as duas datas Period periodo = Period.between(dataInicial, dataFinal); int anos = periodo.getYears(); int meses = periodo.getMonths(); int dias = periodo.getDays(); String s = String.format("Faltam %d ano(s), %d mes(es) e %d dia(s)!", anos, meses, dias); System.out.println(s); // -> Faltam 0 ano(s), 1 mes(es) e 16 dia(s)! //diferença somente em dias long numeroDias = dataInicial.until(dataFinal, ChronoUnit.DAYS); System.out.println(numeroDias + " dias!"); // -> 46 dias!
Não é tudo mas dá pra ter uma idéia. Não sei se você percebeu, mas uma das diferenças é que agora o mês “janeiro” é representado pelo número ‘1’, e não mais como ‘0’ que nem acontecia na API antiga. Um ser humano evoluído conseguiu perceber que nós não gostamos de tratar meses começando de zero! 🙂
Baixem o JDK 8 e façam seus testes. Ainda há tempo inclusive de sugerir mudanças à equipe da JSR 310!
May the force be with you 🙂