Implementando Datas e Horas em Java com API Moderna

A classe java.util.Date herdada do JDK apresenta dseafios significativos. Seu construtor exige que o ano seja calculado a partir de 1900 e os meses comecem em zero, o que leva a erros itnuitivos. Além disso, a classe SimpleDateFormat não é segura para uso em ambientes multithread, causando problemas de concorrência. A API de tempo do Java 8, baseada no pacote java.time, oferece uma alternativa imutável e thread-safe.

Exemplo com a API Legada:

package exemplo.legado;

import java.text.SimpleDateFormat;
import java.util.Date;

public class DemoDateAntigo {
    public static void main(String[] args) {
        // Criação de uma data: ano 2023 (2023 - 1900 = 123), mês junho (5, pois janeiro é 0)
        Date data = new Date(123, 5, 15);
        SimpleDateFormat formato = new SimpleDateFormat("dd/MM/yyyy");
        System.out.println("Data formatada: " + formato.format(data));

        // Problema de concorrência: múltiplas threads usando o mesmo SimpleDateFormat
        Runnable tarefa = () -> {
            try {
                synchronized (formato) {
                    Date parsed = formato.parse("20/06/2023");
                    System.out.println(Thread.currentThread().getName() + " parseou: " + parsed);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        };
        new Thread(tarefa).start();
        new Thread(tarefa).start();
    }
}

LocalDate: Datas Sem Hora

A classe LocalDate representa uma data sem informação de hora ou fuso horário. É imutável e segura para uso em multithreading.

package exemplo.moderno;

import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoField;

public class DemoLocalDate {
    public static void main(String[] args) {
        // Criando uma data específica
        LocalDate dataFixa = LocalDate.of(2023, Month.JUNE, 15);
        System.out.println("Data: " + dataFixa);

        // Extraindo componentes
        int ano = dataFixa.getYear();
        Month mes = dataFixa.getMonth();
        int diaDoMes = dataFixa.getDayOfMonth();
        int diaDoAno = dataFixa.getDayOfYear();
        System.out.printf("Ano: %d, Mês: %s, Dia do Mês: %d, Dia do Ano: %d%n", 
                          ano, mes, diaDoMes, diaDoAno);

        // Usando ChronoField para acesso padronizado
        int mesNumero = dataFixa.get(ChronoField.MONTH_OF_YEAR);
        System.out.println("Mês como número: " + mesNumero);

        // Obtendo a data atual
        LocalDate hoje = LocalDate.now();
        System.out.println("Data de hoje: " + hoje);
    }
}

LocalTime, LocalDateTime, Instant, Duration e Period

LocalTime lida apenas com horas, enquanto LocalDateTime combina data e hora. Instant representa um ponto na linha do tempo (epoch seconds). Duration e Period medem intervalos de tempo.

package exemplo.intervalos;

import java.time.*;
import java.time.temporal.ChronoUnit;

public class DemoTempos {
    public static void main(String[] args) throws InterruptedException {
        // LocalTime
        LocalTime horaAtual = LocalTime.now();
        System.out.println("Hora atual: " + horaAtual);
        System.out.println("Hora: " + horaAtual.getHour() + ", Minuto: " + horaAtual.getMinute());

        // LocalDateTime
        LocalDate data = LocalDate.now();
        LocalTime hora = LocalTime.now();
        LocalDateTime dataHora = LocalDateTime.of(data, hora);
        System.out.println("Data e Hora combinadas: " + dataHora);

        // Instant e Duration (medindo tempo)
        Instant inicio = Instant.now();
        Thread.sleep(1500); // Simula processamento
        Instant fim = Instant.now();
        Duration duracao = Duration.between(inicio, fim);
        System.out.println("Duração em milissegundos: " + duracao.toMillis());

        // Period (diferença entre datas)
        LocalDate inicioPeriodo = LocalDate.of(2020, Month.MARCH, 10);
        LocalDate fimPeriodo = LocalDate.of(2023, Month.JUNE, 15);
        Period periodo = Period.between(inicioPeriodo, fimPeriodo);
        System.out.printf("Período: %d anos, %d meses, %d dias%n", 
                          periodo.getYears(), periodo.getMonths(), periodo.getDays());

        // Calculando diferença em meses usando ChronoUnit
        long mesesTotal = ChronoUnit.MONTHS.between(inicioPeriodo, fimPeriodo);
        System.out.println("Total de meses entre as datas: " + mesesTotal);
    }
}

Formatação e Parsing com DateTimeFormatter

A classe DateTimeFormatter fornece formatação e parsing imutáveis e thread-safe, substituindo SimpleDateFormat.

package exemplo.formatador;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

public class DemoFormatador {
    public static void main(String[] args) {
        // Formatação de LocalDate
        LocalDate hoje = LocalDate.now();
        DateTimeFormatter formatoBasico = DateTimeFormatter.BASIC_ISO_DATE;
        DateTimeFormatter formatoIso = DateTimeFormatter.ISO_LOCAL_DATE;
        DateTimeFormatter formatoCustom = DateTimeFormatter.ofPattern("dd 'de' MMMM 'de' yyyy");

        System.out.println("BASIC_ISO_DATE: " + hoje.format(formatoBasico));
        System.out.println("ISO_LOCAL_DATE: " + hoje.format(formatoIso));
        System.out.println("Customizado: " + hoje.format(formatoCustom));

        // Parsing de strings para LocalDate
        String textoData1 = "20230615";
        String textoData2 = "2023-06-15";
        String textoData3 = "15 de junho de 2023";

        LocalDate parsed1 = LocalDate.parse(textoData1, formatoBasico);
        LocalDate parsed2 = LocalDate.parse(textoData2, formatoIso);
        LocalDate parsed3 = LocalDate.parse(textoData3, formatoCustom);

        System.out.println("Parsed de '20230615': " + parsed1);
        System.out.println("Parsed de '2023-06-15': " + parsed2);
        System.out.println("Parsed de '15 de junho de 2023': " + parsed3);

        // Exemplo com LocalDateTime e formatação completa
        String inputDateTime = "2023-06-15 14:30:00";
        DateTimeFormatter formatterInput = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        DateTimeFormatter formatterOutput = DateTimeFormatter.ofPattern("dd/MM/yyyy HH'h'mm'min'ss's'");

        LocalDateTime dateTime = LocalDateTime.parse(inputDateTime, formatterInput);
        String saidaFormatada = dateTime.format(formatterOutput);
        System.out.println("Saída formatada: " + saidaFormatada);
    }
}

Tags: java localdate localtime LocalDateTime period

Publicado em 5-31 14:29 por Thomas