Introdução à API Java 8 Date/Time

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

Read more

Verifique se uma string é uma data válida em Java

Veja maneiras diferentes de verificar se uma String é uma data válida em Java

Read more

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.