Os desenvolvedores geralmente precisam realizar operações de programação, como recuperar a data atual, manipular datas e formatar datas em seus aplicativos. Embora o Java seja tradicional java.util.Calendar a aula teve seu dia, o mais novo LocalDate class faz mais com significativamente menos linhas de código. Este artigo apresenta a você LocalDate e a java.time API para usar datas, horas e durações em seus programas.

Observação: Introduzido em Java 8, java.time padroniza muitos elementos da popular biblioteca Joda-Time. Os conceitos introduzidos aqui podem ser aplicados a qualquer biblioteca, mas o padrão JDK é geralmente recomendado.

Substitua Calendário por LocalDate

A manipulação de datas do calendário é um aspecto essencial de muitos aplicativos escritos em Java. Tradicionalmente, os desenvolvedores dependiam do java.util.Calendar class para obter a data atual:


Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // Note: Months are zero-based
int day = calendar.get(Calendar.DAY_OF_MONTH);

System.out.println(year + "-" + month + "-" + day);

O LocalDate aula do java-time API oferece uma alternativa mais eficiente::


LocalDate currentDate = LocalDate.now();
System.out.println(currentDate);

Neste exemplo, você vê a diferença entre a verbosidade do tradicional Calendar classe e o mais recente LocalDate aula. A classe mais recente faz mais com muito menos código. A seguir, veremos algumas maneiras simples de usar java.time.LocalDate em seus programas Java.

Maneiras simples de usar LocalDate

Veja como usaríamos LocalDate para retornar a data atual com base no relógio do sistema:


System.out.println(LocalDate.now());

Aqui, criamos um LocalDate instância com o ano, mês e dia especificados:


System.out.println(LocalDate.of(2023, 9, 19));

Neste próximo exemplo, analisamos uma representação de string de uma data e retornamos um LocalDate instância:


String dateString = "2024-04-19";  // ISO-8601 format
LocalDate date = LocalDate.parse(dateString);
System.out.println(date);

Nos casos em que tivermos a data formatada de forma diferente da ISO-8601, poderíamos usar o seguinte:


String dateString = "19/04/2024";  // Custom format
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date = LocalDate.parse(dateString, formatter);
System.out.println(date);

Estes são apenas alguns exemplos do LocalDate classe sendo usada para cenários de aplicação onde a manipulação da data do calendário é necessária. Agora vamos examinar usos mais complexos para LocalDate.

Manipulando componentes de data específicos

Às vezes, precisamos ser capazes de trabalhar com os componentes de uma data, como dia, mês, ano, hora, minuto ou segundo. Exemplos de operações incluem comparar, calcular ou validar informações de data.

Aqui está um exemplo de como chamar componentes de data específicos:


import java.time.LocalDate;

LocalDate date = LocalDate.now();  // Get the current date

System.out.println("Year: " + date.getYear()); // prints the year of the current date
System.out.println("Month: " + date.getMonthValue()); // prints the month of the current date
System.out.println("Day: " + date.getDayOfMonth()); // // prints the day of the current date

System.out.println("Hour: " + dateTime.getHour()); // Prints the hour of the current date
System.out.println("Minute: " + dateTime.getMinute()); // Prints the minute of the current date
System.out.println("Second: " + dateTime.getSecond()); // Prints the second of the current date

Contando dias, meses ou anos

E os casos em que precisamos somar ou subtrair dias, meses ou anos da data do calendário especificada? Veja como LocalDate lida com este caso de uso:


plusDays(int days) - Adds or subtracts the specified days from the date and returns a new LocalDate instance.
minusDays(int days) - Subtracts days from the date.
plusMonths(int months) - Adds the specified number of months to the date and returns a new LocalDate instance.
minusMonths(int months): Subtracts months from the date.
plusYears(int years) - Adds the specified years from the date and returns a new LocalDate instance.
minusYears(int years) - Subtracts years from the date.

Resolvendo o desafio do ano bissexto

Um ano bissexto é um ano civil que contém um dia adicional, ou 366 dias versus os 365 normais. Qualquer programa que use datas de calendário também deve levar em conta anos bissextos. Felizmente, java.timede Year class lida com esse cálculo para nós:


isLeapYear(): Returns true if the year is a leap year

Duas maneiras de comparar datas

Comparar datas é algo que fazemos com frequência na programação. Esta é uma maneira mais antiga de comparar datas usando LocalDate e a compareTo método:


import java.time.LocalDate;

LocalDate date1 = LocalDate.now();  // Create the first date object
LocalDate date2 = LocalDate.now();  // Create the second date object

// Compare dates using the compareTo() method
int comparison = date1.compareTo(date2);

if (comparison < 0) {
    System.out.println("Date 1 is before Date 2");
} else if (comparison > 0) {
    System.out.println("Date 1 is after Date 2");
} else if (comparison == 0) {
    System.out.println("Date 1 is equal to Date 2");
}

Uma maneira mais intuitiva e limpa de comparar datas é usar o isBefore, isAfterou isEqual métodos:


if (date1.isBefore(date2)) {
    System.out.println("Date 1 is before Date 2");
} else if (date1.isAfter(date2)) {
    System.out.println("Date 1 is after Date 2");
} else if (date1.isEqual(date2)) {
    System.out.println("Date 1 is equal to Date 2");
}

Calculando a duração em unidades temporais

Outro requisito comum para aplicativos de negócios é a capacidade de calcular distâncias temporais em unidades temporais. O java.time A API nos permite fazer isso facilmente.

Este exemplo calcula a duração entre dois pontos no tempo medido em horas e minutos:


import java.time.LocalDateTime;
import java.time.Duration;

public class DurationExample {
    public static void main(String() args) {
        LocalDateTime start = LocalDateTime.of(2024, 4, 1, 10, 0);  // April 1, 2024, 10:00
        LocalDateTime end = LocalDateTime.of(2024, 4, 2, 11, 30);   // April 2, 2024, 11:30

        Duration duration = Duration.between(start, end);
        long hours = duration.toHours();
        long minutes = duration.toMinutes() % 60;

        System.out.println("Duration is " + hours + " hours and " + minutes + " minutes.");
    }
}

Neste caso, o tempo de duração é de 25 horas e 30 minutos.

Aqui, calculamos a duração entre duas datas em anos, meses e dias:


import java.time.LocalDate;
import java.time.Period;

public class PeriodExample {
    public static void main(String() args) {
        LocalDate startDate = LocalDate.of(2024, 1, 1);
        LocalDate endDate = LocalDate.of(2024, 12, 31);

        Period period = Period.between(startDate, endDate);
        System.out.println("Period is " + period.getYears() + " years, " +
                           period.getMonths() + " months, and " +
                           period.getDays() + " days.");
    }
}

A saída neste caso é 0 anos, 11 meses e 30 dias.

Lidando com fusos horários

Ao trabalhar em um aplicativo em produção, você pode encontrar bugs devido a fusos horários configurados incorretamente. Às vezes, o aplicativo é implantado em um servidor com fuso horário diferente do país em que é servido. Vejamos maneiras de gerenciar diferenças em fusos horários usando java.time classes e métodos.

Primeiro, podemos usar o ZonedDateTime classe para gerenciar uma data e hora com informações de fuso horário. Veja como obter a hora atual para dois fusos horários específicos:


import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class TimeZoneExample {
    public static void main(String() args) {
        ZoneId newYorkZone = ZoneId.of("America/New_York");
        ZoneId londonZone = ZoneId.of("Europe/London");
        
        ZonedDateTime nowInNewYork = ZonedDateTime.now(newYorkZone);
        ZonedDateTime nowInLondon = ZonedDateTime.now(londonZone);
        
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        System.out.println("Current time in New York: " + nowInNewYork.format(formatter));
        System.out.println("Current time in London: " + nowInLondon.format(formatter));
    }
}

Se executarmos este código em 19 de abril de 2024, às 12h UTC, a saída seria a seguinte:

  • Hora local em Nova York: 19/04/2024 08:00:00
  • Hora local em Londres: 19/04/2024 13:00:00

Que tal converter entre fusos horários? Veja como converter um determinado horário de uma zona para outra:


import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class TimeZoneConversion {
    public static void main(String() args) {
        LocalDateTime localDateTime = LocalDateTime.of(2024, 4, 19, 15, 30);
        ZoneId originalZone = ZoneId.of("Asia/Tokyo");
        ZoneId targetZone = ZoneId.of("America/Los_Angeles");

        ZonedDateTime originalZonedDateTime = ZonedDateTime.of(localDateTime, originalZone);
        ZonedDateTime targetZonedDateTime = originalZonedDateTime.withZoneSameInstant(targetZone);

        System.out.println("Time in Tokyo: " + originalZonedDateTime);
        System.out.println("Time in Los Angeles: " + targetZonedDateTime);
    }
}

A saída neste caso seria:

  • Horário em Tóquio: 2024-04-19T15:30+09:00(Ásia/Tóquio)
  • Horário em Los Angeles: 2024-04-19T01:30-07:00(América/Los_Angeles)

Transições para horário de verão

As transições do horário de verão (DST) podem interromper a funcionalidade do seu aplicativo se não forem tratadas adequadamente. Veja como lidar com uma transição de horário de verão usando o ZonedDateTime aula:


import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class TimeZoneConversion {
    public static void main(String() args) {
        LocalDateTime localDateTime = LocalDateTime.of(2024, 4, 19, 15, 30);
        ZoneId originalZone = ZoneId.of("Asia/Tokyo");
        ZoneId targetZone = ZoneId.of("America/Los_Angeles");

        ZonedDateTime originalZonedDateTime = ZonedDateTime.of(localDateTime, originalZone);
        ZonedDateTime targetZonedDateTime = originalZonedDateTime.withZoneSameInstant(targetZone);

        System.out.println("Time in Tokyo: " + originalZonedDateTime);
        System.out.println("Time in Los Angeles: " + targetZonedDateTime);
    }
}

Aqui está o resultado deste cálculo:

  • Antes do final do horário de verão: 2024-11-03T01:30-04:00(América/Nova_Iorque)
  • Após o término do horário de verão: 2024-11-03T01:30-05:00(América/Nova_Iorque)

Conclusão

Os desenvolvedores lidam com datas e horários na maioria dos aplicativos. O java.time API incorpora elementos do obsoleto joda-time biblioteca e os padroniza do Java 8 em diante. Como você viu neste artigo, java.time oferece muitas construções poderosas para gerenciar data e hora em seus aplicativos.

Vamos recapitular os principais pontos deste artigo:

  • O java.time O pacote fornece uma abordagem mais clara e intuitiva para lidar com datas e horas em comparação com o tradicional java.util.Calendar aula.
  • Usando java.time permite realizar operações como recuperar a data atual, manipular datas e formatar com menos linhas de código e menos complexidade.
  • java.time Funções de API como plusDays() e minusMonths() suporta aritmética de data simples que é mais complicada de fazer com o Calendar aula.
  • Métodos mais recentes, como isBefore(), isAfter()e isEqual() oferecem uma maneira mais legível e direta de comparar datas do que usar compareTo().
  • ZonedDateTime simplifica o gerenciamento avançado de fuso horário e os cálculos de horário de verão, fornecendo ferramentas robustas para aplicações globais.
  • O java.time A biblioteca oferece suporte a poderosas opções de formatação e análise de data que são mais fáceis de usar e entender do que as classes tradicionais de data e hora Java, melhorando a legibilidade e a manutenção do código.
  • A moderna biblioteca de data e hora foi projetada para ser imutável e segura para threads, o que resulta em menos efeitos colaterais e erros em ambientes multithread.

Para novos projetos ou ao manter aplicações Java existentes, recomenda-se fazer a transição para o java.time API por seu tratamento mais eficiente, claro e robusto de operações de data e hora.