Migrando para a nova API de data e hora do Java 8
1. Visão geral
Neste tutorial, você aprenderá como refatorar seu código para aproveitar a nova API de Data e Hora introduzida no Java 8.
2. Visão geral da nova API
Trabalhar com datas em Java costumava ser difícil. A antiga biblioteca de datas fornecida pelo JDK incluía apenas três classes:java.util.Date, java.util.Calendarejava.util.Timezone.
Estes eram adequados apenas para as tarefas mais básicas. Para qualquer coisa remotamente complexa, os desenvolvedores tiveram que usar bibliotecas de terceiros ou escrever toneladas de código personalizado.
Java 8 introduced a completely new Date Time API (java.util.time.*) que é vagamente baseado na popular biblioteca Java chamada JodaTime. Essa nova API simplificou drasticamente o processamento de data e hora e corrigiu muitas deficiências da antiga biblioteca de datas.
1.1. Clareza API
Uma primeira vantagem da nova API éclarity - a API é muito clara, concisa e fácil de entender. Ele não possui muitas inconsistências encontradas na biblioteca antiga, como a numeração de campos (nos meses do calendário são baseados em zero, mas os dias da semana são baseados em uma).
1.2. Flexibilidade API
Outra vantagem é a flexibilidade -working with multiple representations of time. A biblioteca de data antiga incluía apenas uma única classe de representação de tempo -java.util.Date, que, apesar do nome, é na verdade um carimbo de data / hora. Ele armazena apenas o número de milissegundos decorridos desde a época do Unix.
A nova API possui muitas representações de tempo diferentes, cada uma adequada para diferentes casos de uso:
-
Instant - representa um ponto no tempo (timestamp)
-
LocalDate - representa uma data (ano, mês, dia)
-
LocalDateTime - igual aLocalDate, mas inclui o tempo com precisão de nanossegundos
-
OffsetDateTime - igual aLocalDateTime, mas com deslocamento de fuso horário
-
LocalTime - tempo com precisão de nanossegundos e sem informação de data
-
ZonedDateTime - igual aOffsetDateTime, mas inclui um ID de fuso horário
-
OffsetLocalTime - igual aLocalTime, mas com deslocamento de fuso horário
-
MonthDay - mês e dia, sem ano ou hora
-
YearMonth - mês e ano, sem dia ou hora
-
Duration - quantidade de tempo representada em segundos, minutos e horas. Possui precisão de nanossegundos
-
Period - quantidade de tempo representada em dias, meses e anos
1.3. Imutabilidade e segurança da linha
Outra vantagem é que todas as representações de tempo na API Java 8 Date Time sãoimmutable and thus thread-safe.
Todos os métodos de mutação retornam uma nova cópia em vez de modificar o estado do objeto original.
Classes antigas, comojava.util.Date, não eram seguras para threads e podiam introduzir bugs de simultaneidade muito sutis.
1.4. Encadeamento de método
Todos os métodos de mutação podem ser encadeados, permitindo implementar transformações complexas em uma única linha de código.
ZonedDateTime nextFriday = LocalDateTime.now()
.plusHours(1)
.with(TemporalAdjusters.next(DayOfWeek.FRIDAY))
.atZone(ZoneId.of("PST"));
2. Exemplos
Os exemplos abaixo demonstram como executar tarefas comuns com a API antiga e nova.
Obtendo hora atual
// Old
Date now = new Date();
// New
ZonedDateTime now = ZonedDateTime.now();
Representando um tempo específico
// Old
Date birthDay = new GregorianCalendar(1990, Calendar.DECEMBER, 15).getTime();
// New
LocalDate birthDay = LocalDate.of(1990, Month.DECEMBER, 15);
Extraindo campos específicos
// Old
int month = new GregorianCalendar().get(Calendar.MONTH);
// New
Month month = LocalDateTime.now().getMonth();
Adicionando e subtraindo tempo
// Old
GregorianCalendar calendar = new GregorianCalendar();
calendar.add(Calendar.HOUR_OF_DAY, -5);
Date fiveHoursBefore = calendar.getTime();
// New
LocalDateTime fiveHoursBefore = LocalDateTime.now().minusHours(5);
Alterando campos específicos
// Old
GregorianCalendar calendar = new GregorianCalendar();
calendar.set(Calendar.MONTH, Calendar.JUNE);
Date inJune = calendar.getTime();
// New
LocalDateTime inJune = LocalDateTime.now().withMonth(Month.JUNE.getValue());
Truncando
Truncar redefine todos os campos de tempo menores que o campo especificado. No exemplo abaixo, minutos e tudo abaixo será definido como zero
// Old
Calendar now = Calendar.getInstance();
now.set(Calendar.MINUTE, 0);
now.set(Calendar.SECOND, 0);
now.set(Calendar.MILLISECOND, 0);
Date truncated = now.getTime();
// New
LocalTime truncated = LocalTime.now().truncatedTo(ChronoUnit.HOURS);
Conversão de fuso horário
// Old
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeZone(TimeZone.getTimeZone("CET"));
Date centralEastern = calendar.getTime();
// New
ZonedDateTime centralEastern = LocalDateTime.now().atZone(ZoneId.of("CET"));
Obtendo intervalo de tempo entre dois pontos no tempo
// Old
GregorianCalendar calendar = new GregorianCalendar();
Date now = new Date();
calendar.add(Calendar.HOUR, 1);
Date hourLater = calendar.getTime();
long elapsed = hourLater.getTime() - now.getTime();
// New
LocalDateTime now = LocalDateTime.now();
LocalDateTime hourLater = LocalDateTime.now().plusHours(1);
Duration span = Duration.between(now, hourLater);
Formatação e análise de hora
DateTimeFormatter é um substituto para o SimpleDateFormat antigo que é seguro para threads e fornece funcionalidade adicional.
// Old
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
Date now = new Date();
String formattedDate = dateFormat.format(now);
Date parsedDate = dateFormat.parse(formattedDate);
// New
LocalDate now = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formattedDate = now.format(formatter);
LocalDate parsedDate = LocalDate.parse(formattedDate, formatter);
Número de dias em um mês
// Old
Calendar calendar = new GregorianCalendar(1990, Calendar.FEBRUARY, 20);
int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
// New
int daysInMonth = YearMonth.of(1990, 2).lengthOfMonth();
3. Interagindo com o código legado
Em muitos casos, um usuário pode precisar garantir a interoperabilidade com bibliotecas de terceiros que dependem da biblioteca de datas antiga.
No Java 8, as classes de bibliotecas de datas antigas foram estendidas com métodos que as convertem em objetos correspondentes da nova API de data. Novas classes fornecem funcionalidades semelhantes.
Instant instantFromCalendar = GregorianCalendar.getInstance().toInstant();
ZonedDateTime zonedDateTimeFromCalendar = new GregorianCalendar().toZonedDateTime();
Date dateFromInstant = Date.from(Instant.now());
GregorianCalendar calendarFromZonedDateTime = GregorianCalendar.from(ZonedDateTime.now());
Instant instantFromDate = new Date().toInstant();
ZoneId zoneIdFromTimeZone = TimeZone.getTimeZone("PST").toZoneId();
4. Conclusão
Neste artigo, exploramos a nova API de data e hora disponível no Java 8. Examinamos suas vantagens em comparação com a API descontinuada e apontamos diferenças usando vários exemplos.
Observe que mal arranhamos a superfície dos recursos da nova API de data e hora. Leia a documentação oficial para descobrir a gama completa de ferramentas oferecidas pela nova API.
Os exemplos de código podem ser encontrados emGitHub project.