Java SE 8: A Nova API de Data e Hora em Java

Os desenvolvedores Java frequentemente enfrentavam limitações significativas ao trabalhar com datas e horários devido às bibliotecas herdadas. As classes tradicionais, como java.util.Date e SimpleDateFormat, apresentavam problemas sérios de segurança em ambientes multi-thread, além de design não intuitivo - por exemplo, no java.util.Date, o ano era representado a partir de 1900 e os meses começavam em 0. Essas deficiências levavam muitos a recorrerem a bibliotecas externas como Joda-Time.

Para resolver esses problemas de forma padronizada, o Java SE 8 introduziu uma nova API de data e hora através do JSR-310, desenvolvida em colaboração com a Oracle e os criadores da Joda-Time, agora incorporada no pacote java.time.

Fundamentos da Nova Arquitetura

A nova API baseia-se em três princípios fundamentais:

  • Imutabilidade: Todas as classes principais são imutáveis, eliminando problemas de concorrência que afetavam os formatadores antigos.
  • Modelagem de Domínio: Separação clara entre conceitos de data, tempo e ponto temporal. Enquanto java.util.Date representava confusamente um instante no tempo com elementos de timezone no toString(), a nova API mantém distinções claras.
  • Suporte a Calendários Regionais: Flexibilidade para trabalhar com diferentes sistemas temporais além do ISO-8601, como calendários usados no Japão ou Tailândia.

Classes Fundamentais

As classes LocalDate e LocalTime representam respectivamente data e tempo sem informação de fuso horário, refletindo o ambiente local do sistema. A classe LocalDateTime combina ambas as representações.

Criação e Manipulação

As instâncias são criadas através de métodos de fábrica, proporcionando clareza e segurança. A seguir, exemplos de inicialização:

LocalDateTime instante = LocalDateTime.now();
LocalDate dataEspecifica = LocalDate.of(2023, Month.MARCH, 15);
LocalDate epoca = LocalDate.ofEpochDay(200);
LocalTime partida = LocalTime.of(8, 30);
LocalTime textoParaTempo = LocalTime.parse("14:45:00");

Acesso aos componentes temporais utiliza métodos convencionais de getter:

LocalDate apenasData = instante.toLocalDate();
Month mesCorrente = instante.getMonth();
int diaDoMes = instante.getDayOfMonth();
int segundos = instante.getSecond();

Como os objetos são imutáveis, operações de modificação retornam novas instâncias:

LocalDateTime modificado = instante.withDayOfMonth(1)
                                  .withYear(2022);
LocalDateTime avancado = modificado.plusWeeks(2)
                                   .plus(5, ChronoUnit.DAYS);

A API enclui o conceito de Ajustadores Temporais para encapsular lógica comum de manipulação:

import static java.time.temporal.TemporalAdjusters.*;

LocalDateTime referencia = ...;
LocalDateTime finalMes = referencia.with(lastDayOfMonth());
LocalDateTime quartaProxima = referencia.with(nextOrSame(ChronoUnit.WEDNESDAY));
referencia.with(LocalTime.of(18, 0));

Truncamento Temporal

O método truncatedTo permite reduzir a precisão de um objeto temporal:

LocalTime tempoReduzido = horario.truncatedTo(ChronoUnit.MINUTES);

Fusos Horários e Ofsets

A nova API fornece uma modelagem robusta para fusos horários, representados por ZoneId (identificador como "America/Sao_Paulo") e ZoneOffset (diferença em relação ao UTC).

ZoneId zona = ZoneId.of("Asia/Tokyo");
ZonedDateTime horarioComZona = ZonedDateTime.of(instante, zona);

ZoneOffset deslocamento = ZoneOffset.of("-03:00");

Classes com Informação de Fuso

  • ZonedDateTime: Data, hora e fuso horário completo, ideal para representar eventos em contextos globais.
  • OffsetDateTime: Data, hora e deslocamento numérico, útil para persistência em bancos de dados.
  • OffsetTime: Apenas hora com deslocamento.
ZonedDateTime eventoGlobal = ZonedDateTime.parse("2024-05-20T09:30:00-04:00[America/New_York]");

OffsetDateTime registroBanco = OffsetDateTime.now(deslocamento);
OffsetTime horaLocal = OffsetTime.now();
OffsetTime mesmaInstanteDiferenteOfset = horaLocal.withOffsetSameInstant(deslocamento);
OffsetTime mesmaHoraDiferenteOfset = horaLocal.withOffsetSameLocal(deslocamento);

Períodos e Durações

A classe Period representa durações baseadas em unidades de calendário (anos, meses, dias):

Period intervalo = Period.ofMonths(3).plusDays(10);
LocalDate novaData = dataAnterior.plus(intervalo);

Duration representa durações em unidades de tempo precisas (segundos, nanossegundos):

Duration espera = Duration.ofMinutes(45);
Duration intervaloExato = Duration.between(horaInicio, horaFim);

Outras Classes Utilitárias

Para casos específicos, existem classes como MonthDay (para aniversários ou feriados) e YearMonth (para faturas ou planos de assinatura).

A integração com JDBC suporta os tipos ANSI SQL equivalentes:

Tipo SQL Classe Java
DATE LocalDate
TIME LocalTime
TIMESTAMP LocalDateTime
TIMESTAMP WITH TIMEZONE OffsetDateTime

Tags: java java.time datetime-api java-se8 joda-time

Publicado em 6-21 00:59