Introdução à API Java 8 Date / Time
1. Visão geral
Java 8 introduziu novas APIs paraDateeTime para tratar das deficiências dosjava.util.Dateejava.util.Calendar mais antigos.
Como parte deste artigo, vamos começar com os problemas nas APIsDateeCalendar existentes e vamos discutir como as novas APIs Java 8DateeTime os resolvem.
Também veremos algumas das classes principais do novo projeto Java 8 que fazem parte do pacotejava.time, comoLocalDate,LocalTime, LocalDateTime, ZonedDateTime, Period, Duratione suas APIs com suporte.
Leitura adicional:
Trabalhando com parâmetros de data no Spring
Aprenda a trabalhar com parâmetros de data no Spring MVC
Verifique se uma string é uma data válida em Java
Veja maneiras diferentes de verificar se uma String é uma data válida em Java
2. Problemas com APIsDate /Time existentes
-
Thread Safety - As classesDateeCalendar não são thread-safe, deixando os desenvolvedores lidando com a dor de cabeça de problemas de simultaneidade difíceis de depurar e escrever código adicional para lidar com a segurança de thread. Ao contrário, as novas APIsDateeTime introduzidas no Java 8 são imutáveis e seguras para threads, tirando assim a dor de cabeça de simultaneidade dos desenvolvedores.
-
APIs Design and Ease of Understanding - As APIsDate eCalendar são mal projetadas com métodos inadequados para executar operações diárias. As novas APIsDate/Time são centradas em ISO e seguem modelos de domínio consistentes para data, hora, duração e períodos. Há uma grande variedade de métodos utilitários que suportam as operações mais comuns.
-
ZonedDate and Time - os desenvolvedores tiveram que escrever lógica adicional para lidar com a lógica do fuso horário com as APIs antigas, enquanto com as novas APIs, o tratamento do fuso horário pode ser feito comLocaleZonedDate /Time APIs.
3. UsandoLocalDate,LocalTime eLocalDateTime
As classes mais comumente usadas sãoLocalDate,LocalTimeeLocalDateTime. Como seus nomes indicam, eles representam a Data / Hora local do contexto do observador.
Essas classes são usadas principalmente quando não é necessário especificar explicitamente o fuso horário no contexto. Como parte desta seção, abordaremos as APIs mais usadas.
3.1. Trabalhando comLocalDate
OLocalDate representaa date in ISO format (yyyy-MM-dd) without time.
Pode ser usado para armazenar datas como aniversários e dias de pagamento.
Uma instância da data atual pode ser criada a partir do relógio do sistema, como abaixo:
LocalDate localDate = LocalDate.now();
OsLocalDate representando um dia, mês e ano específicos podem ser obtidos usando o método “of” ou usando o método “parse”. Por exemplo, os snippets de código abaixo representamLocalDate para 20 de fevereiro de 2015:
LocalDate.of(2015, 02, 20);
LocalDate.parse("2015-02-20");
OLocalDate fornece vários métodos utilitários para obter uma variedade de informações. Vamos dar uma olhada rápida em alguns desses métodos de APIs.
O seguinte snippet de código obtém a data local atual e adiciona um dia:
LocalDate tomorrow = LocalDate.now().plusDays(1);
Este exemplo obtém a data atual e subtrai um mês. Observe como ele aceitaenum como unidade de tempo:
LocalDate previousMonthSameDay = LocalDate.now().minus(1, ChronoUnit.MONTHS);
Nos dois exemplos de código a seguir, analisamos a data "12/06/2016" e obtemos o dia da semana e o dia do mês, respectivamente. Observe os valores de retorno, o primeiro é um objeto que representa oDayOfWeek, enquanto o segundo em umint que representa o valor ordinal do mês:
DayOfWeek sunday = LocalDate.parse("2016-06-12").getDayOfWeek();
int twelve = LocalDate.parse("2016-06-12").getDayOfMonth();
Podemos testar se uma data ocorre em um ano bissexto. Neste exemplo, testamos se a data atual ocorre é um ano bissexto:
boolean leapYear = LocalDate.now().isLeapYear();
O relacionamento de uma data para outra pode ser determinado como ocorrendo antes ou depois de outra data:
boolean notBefore = LocalDate.parse("2016-06-12")
.isBefore(LocalDate.parse("2016-06-11"));
boolean isAfter = LocalDate.parse("2016-06-12")
.isAfter(LocalDate.parse("2016-06-11"));
Os limites de datas podem ser obtidos a partir de uma determinada data. Nos dois exemplos a seguir, obtemos oLocalDateTime que representa o início do dia (2016-06-12T00: 00) da data fornecida e oLocalDate que representa o início do mês (2016- 06-01) respectivamente:
LocalDateTime beginningOfDay = LocalDate.parse("2016-06-12").atStartOfDay();
LocalDate firstDayOfMonth = LocalDate.parse("2016-06-12")
.with(TemporalAdjusters.firstDayOfMonth());
Agora vamos dar uma olhada em como trabalhamos com a hora local.
3.2. Trabalhando comLocalTime
OLocalTime representatime without a date.
Semelhante aLocalDate, uma instância deLocalTime pode ser criada a partir do relógio do sistema ou usando o método “parse” e “of”. Veja rapidamente algumas das APIs mais usadas abaixo.
Uma instância doLocalTime atual pode ser criada a partir do relógio do sistema conforme abaixo:
LocalTime now = LocalTime.now();
No exemplo de código a seguir,, criamos umLocalTime que representa 06h30 analisando uma representação de string:
LocalTime sixThirty = LocalTime.parse("06:30");
O método de fábrica “de” pode ser usado para criar umLocalTime. Por exemplo, o código abaixo criaLocalTime representando 06:30 AM usando o método de fábrica:
LocalTime sixThirty = LocalTime.of(6, 30);
O exemplo abaixo cria umLocalTime analisando uma string e adiciona uma hora a ela usando a API “plus”. O resultado seriaLocalTime representando 07:30:
LocalTime sevenThirty = LocalTime.parse("06:30").plus(1, ChronoUnit.HOURS);
Estão disponíveis vários métodos getter que podem ser usados para obter unidades de tempo específicas, como horas, min e segundos, como abaixo:
int six = LocalTime.parse("06:30").getHour();
Também podemos verificar se um horário específico é anterior ou posterior a outro horário específico. O exemplo de código a seguir compara doisLocalTime para os quais o resultado seria verdadeiro:
boolean isbefore = LocalTime.parse("06:30").isBefore(LocalTime.parse("07:30"));
Os horários máx., Mín. E meio-dia de um dia podem ser obtidos por constantes na classeLocalTime. Isso é muito útil ao executar consultas ao banco de dados para encontrar registros dentro de um determinado período de tempo. Por exemplo, o código abaixo representa 23: 59: 59.99:
LocalTime maxTime = LocalTime.MAX
Agora vamos mergulhar emLocalDateTime.
3.3. Trabalhando comLocalDateTime
OLocalDateTime é usado para representara combination of date and time.
Essa é a classe mais usada quando precisamos de uma combinação de data e hora. A classe oferece uma variedade de APIs e veremos algumas das mais usadas.
Uma instância deLocalDateTime pode ser obtida a partir do relógio do sistema semelhante aLocalDateeLocalTime:
LocalDateTime.now();
Os exemplos de código abaixo explicam como criar uma instância usando os métodos factory "of" e "parse". O resultado seria uma instânciaLocalDateTime representando 20 de fevereiro de 2015, 06:30:
LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);
LocalDateTime.parse("2015-02-20T06:30:00");
Existem APIs de utilidade para dar suporte à adição e subtração de unidades de tempo específicas, como dias, meses, ano e minutos. Os exemplos de código abaixo demonstram o uso dos métodos "mais" e "menos". Essas APIs se comportam exatamente como suas contrapartes emLocalDateeLocalTime:
localDateTime.plusDays(1);
localDateTime.minusHours(2);
Os métodos Getter estão disponíveis para extrair unidades específicas semelhantes às classes de data e hora. Dada a instância acima deLocalDateTime, o exemplo de código abaixo retornará o mês de fevereiro:
localDateTime.getMonth();
4. Usando APIZonedDateTime
Java 8 provides ZonedDateTime # [.typ] #quando precisamos lidar com a data e hora específicas do fuso horário. OZoneId é um identificador usado para representar zonas diferentes. Existem cerca de 40 fusos horários diferentes e osZoneId são usados para representá-los como segue.
Neste snippet de código, criamos umZone para Paris:
ZoneId zoneId = ZoneId.of("Europe/Paris");
Um conjunto de todos os IDs de zona pode ser obtido como abaixo:
Set allZoneIds = ZoneId.getAvailableZoneIds();
OLocalDateTime pode ser convertido para uma zona específica:
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
OZonedDateTime fornece o métodoparse para obter a data e hora específica do fuso horário:
ZonedDateTime.parse("2015-05-03T10:15:30+01:00[Europe/Paris]");
Outra maneira de trabalhar com fuso horário é usandoOffsetDateTime. OOffsetDateTime é uma representação imutável de uma data e hora com um deslocamento. Esta classe armazena todos os campos de data e hora, com precisão de nanossegundos, bem como o deslocamento do UTC / Greenwich.
A instânciaOffSetDateTime pode ser criada conforme abaixo usandoZoneOffset. Aqui, criamos umLocalDateTime representando 6h30 em 20 de fevereiro de 2015:
LocalDateTime localDateTime = LocalDateTime.of(2015, Month.FEBRUARY, 20, 06, 30);
Em seguida, adicionamos duas horas ao tempo criando umZoneOffsete definindo a instâncialocalDateTime:
ZoneOffset offset = ZoneOffset.of("+02:00");
OffsetDateTime offSetByTwo = OffsetDateTime
.of(localDateTime, offset);
Agora temos umlocalDateTime de 2015-02-20 06:30 +02: 00. Agora vamos ver como modificar os valores de data e hora usando as classesPeriodeDuration.
5. UsandoPeriod eDuration
A classePeriod representa uma quantidade de tempo em termos de anos, meses e dias e a classeDuration representa uma quantidade de tempo em termos de segundos e nano segundos.
5.1. Trabalhando comPeriod
A classePeriod é amplamente usada para modificar valores de uma determinada data ou para obter a diferença entre duas datas:
LocalDate initialDate = LocalDate.parse("2007-05-10");
ODate pode ser manipulado usandoPeriod, conforme mostrado no seguinte trecho de código:
LocalDate finalDate = initialDate.plus(Period.ofDays(5));
A classePeriod tem vários métodos getter, comogetYears, getMonthsegetDays, para obter valores de um objetoPeriod. O exemplo de código a seguir retorna um valorint de 5 conforme tentamos obter a diferença em termos de dias:
int five = Period.between(initialDate, finalDate).getDays();
OPeriod entre duas datas pode ser obtido em uma unidade específica, como dias ou mês ou anos, usandoChronoUnit.between:
long five = ChronoUnit.DAYS.between(initialDate, finalDate);
Este exemplo de código retorna cinco dias. Vamos continuar dando uma olhada na classeDuration.
5.2. Trabalhando comDuration
Semelhante aPeriod,, oDuration class é usado para lidar comTime. No código a seguir, criamos umLocalTime de 6h30 e, em seguida, adicionamos uma duração de 30 segundos para fazer aLocalTime de 06:30:30:
LocalTime initialTime = LocalTime.of(6, 30, 0);
LocalTime finalTime = initialTime.plus(Duration.ofSeconds(30));
ODuration entre dois instantes pode ser obtido comoDuration ou como uma unidade específica. No primeiro trecho de código, usamos o métodobetween() da classeDuration para encontrar a diferença de tempo entrefinalTimeeinitialTimee retornar a diferença em segundos:
long thirty = Duration.between(initialTime, finalTime).getSeconds();
No segundo exemplo, usamos o métodobetween() da classeChronoUnit para realizar a mesma operação:
long thirty = ChronoUnit.SECONDS.between(initialTime, finalTime);
Agora veremos como converterDate eCalendar existentes em novosDate /Time.
6. Compatibilidade comDate eCalendar
Java 8 adicionou o métodotoInstant() que ajuda a converter a instânciaDate eCalendar existente para a nova API Date Time como no seguinte trecho de código:
LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
LocalDateTime.ofInstant(calendar.toInstant(), ZoneId.systemDefault());
OLocalDateTime pode ser construído a partir de segundos de época, conforme abaixo. O resultado do código abaixo seria umLocalDateTime representando 2016-06-13T11: 34: 50:
LocalDateTime.ofEpochSecond(1465817690, 0, ZoneOffset.UTC);
Agora, vamos passar para a formatação deDateeTime.
7. Formatação deDate eTime
Java 8 fornece APIs para a formatação fácil deDateeTime: __
LocalDateTime localDateTime = LocalDateTime.of(2015, Month.JANUARY, 25, 6, 30);
O código abaixo passa um formato de data ISO para formatar a data local. O resultado seria 25-0 2015:
String localDateString = localDateTime.format(DateTimeFormatter.ISO_DATE);
ODateTimeFormatter fornece várias opções de formatação padrão. Os padrões personalizados também podem ser fornecidos para formatar o método, como abaixo, que retornaria umLocalDate como 2015/01/25:
localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
Podemos passar o estilo de formatação comoSHORT,LONG ouMEDIUM como parte da opção de formatação. O exemplo de código abaixo daria uma saída representandoLocalDateTime em 25 de janeiro de 2015, 06:30:00:
localDateTime
.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM))
.withLocale(Locale.UK);
Vamos dar uma olhada nas alternativas disponíveis para APIs Java 8 CoreDate /Time.
8. Backport e opções alternativas
8.1. Usando o Projeto Threeten
Para organizações que estão migrando do Java 7 ou Java 6 para o Java 8 e desejam usar a API de data e hora, o projetothreeten fornece o recurso de backport. Os desenvolvedores podem usar as classes disponíveis neste projeto para obter a mesma funcionalidade da nova API Java 8DateeTime e, uma vez que mudem para o Java 8, os pacotes podem ser trocados. O artefato para o projeto três pode ser encontrado emmaven central repository:
org.threeten
threetenbp
1.3.1
8.2. Biblioteca Joda-Time
Outra alternativa para a biblioteca Java 8DateeTime é a bibliotecaJoda-Time. Na verdade, as APIs do Java 8Date Time foram lideradas conjuntamente pelo autor da biblioteca Joda-Time (Stephen Colebourne) e pela Oracle. Esta biblioteca oferece praticamente todos os recursos suportados no projeto Java 8Date Time. O artefato pode ser encontrado emmaven central incluindo a dependência de pom abaixo em seu projeto:
joda-time
joda-time
2.9.4
9. Conclusão
O Java 8 fornece um rico conjunto de APIs com design consistente da API para facilitar o desenvolvimento.
Os exemplos de código para o artigo acima podem ser encontrados no repositório gitJava 8 Date/Time.