Domine a API de Datas do Java 8 - Conceitos Básicos

As Classes Legadas: java.util.Date, java.sql.Date e java.util.Calendar

java.util.Date

Esta é a classe clássica para representar o tempo, contendo ano, mês, dia, hora, minuto e segundo, com precisão de milissegundos. Ela preserva apanas dois construtores que não foram depreciados.

Date instanteAtual = new Date();
System.out.println("Data/Hora atual: " + instanteAtual);
// Saída: "Data/Hora atual: Sat Aug 14 17:38:49 CST 2021"
// Na verdade, retorna o tempo em segundos mais próximo ao milissegundo atual.

long milissegundosAtuais = instanteAtual.getTime();
// Cria um Date passando milissegundos desde 1 de janeiro de 1970, 00:00:00 GMT
Date instanteFuturo = new Date(milissegundosAtuais + 1000*1000);
System.out.println(instanteFuturo);
// Saída: "Sat Aug 14 17:55:29 CST 2021"

Principais métodos:

// Retorna milissegundos desde 1 de janeiro de 1970, 00:00:00 GMT
data.getTime()
// Compara duas datas: retorna -1 se anterior, 0 se igual, 1 se posterior.
data.compareTo(Date outraData)
// Verifica se a data é anterior/posterior, baseando-se nos milissegundos.
data.before(Date outraData)
data.after(Date outraData)

A classe Date utiliza java.text.SimpleDateFormat para formatação, retornando uma String. Da mesma forma, pode-se analisar (parse) uma String para obter uma Date, desde que o formato seja idêntico; caso contrário, retorna null.

// Formatação
SimpleDateFormat formato12h = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); // hh para 12 horas
SimpleDateFormat formato24h = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // HH para 24 horas

String textoData1 = formato12h.format(instanteAtual);
System.out.println(textoData1);
// Saída: 2021-08-14 06:41:54

String textoData2 = formato24h.format(instanteAtual);
System.out.println(textoData2);
// Saída: 2021-08-14 18:41:54
        
// Análise (parse): a String DEVE estar no formato "yyyy-MM-dd HH:mm:ss"
Date dataParseada = formato24h.parse(textoData2, new ParsePosition(0)); // ParsePosition(0) analisa a string inteira.

java.sql.Date

java.sql.Date estende java.util.Date. A diferença principal é que seu construtor aceita apenas milissegundos. Ela corresponde ao tipo DATE do SQL, zerando horas, minutos, segundos e milissegundos. Pode ser convertida para LocalDate do Java 8.

java.sql.Date dataSQL = new java.sql.Date(100000000);
System.out.println(dataSQL);
// Saída: 1970-01-02

LocalDate localDateConvertida = dataSQL.toLocalDate();
System.out.println(localDateConvertida);

java.sql.Time corresponde ao tipo TIME do SQL.

java.sql.Time tempoSQL = new java.sql.Time(1000000000);
System.out.println(tempoSQL);
// Saída: 21:46:40

java.sql.Timestamp corresponde ao tipo TIMESTAMP do SQL, com precisão de nanossegundos.

java.sql.Timestamp timestampSQL = new java.sql.Timestamp(1000000000);
System.out.println(timestampSQL);
// Saída: 1970-01-12 21:46:40.0

java.util.Calendar

java.util.Calendar é uma classe abstrata que pode armazenar ano, mês, dia, hora, minuto e segundo, além de realizar operações de adição e subtração. Seu principal propósito é oferecer métodos flexíveis para manipulação de campos de data, como converter entre ano, mês, dia e dia da semana (por exemplo, encontrar o último dia do mês ou quantas semanas tem o ano).

Nota: No Calendar, a semana começa em SUNDAY (1) e termina em SATURDAY (7). Os meses vão de JANUARY (0) a DECEMBER (11).

Calendar calendario = Calendar.getInstance();
Date dataDoCalendario = calendario.getTime();
// ou
int ano = calendario.get(Calendar.YEAR);
int mes = calendario.get(Calendar.MONTH) + 1; // Ajuste para 1-12
int dia = calendario.get(Calendar.DAY_OF_MONTH);
int hora = calendario.get(Calendar.HOUR_OF_DAY); // Formato 24h
int minuto = calendario.get(Calendar.MINUTE);
int segundo = calendario.get(Calendar.SECOND);

As Novas Classes do Java 8: java.time

No Java 8, foram introduzidas três novas classes imutáveis e thread-safe: LocalDate, LocalTime e LocalDateTime, representando data, tempo e data+tempo, respectivamente.

java.time.LocalDate

LocalDate armazena apenas a data (ano, mês, dia). Permite obter o dia da semana, útil, por exemplo, para gerar um calendário. Oferece uma API mais rica e segura que as classes antigas.

// Construção
LocalDate hoje = LocalDate.now();
LocalDate diaEspecifico = LocalDate.of(2021, 8, 15);
System.out.println("Formato padrão LocalDate: " + hoje);
System.out.println("Dia da semana: " + hoje.getDayOfWeek() + ", Mês: " + hoje.getMonthValue() + ", Dia do ano: " + hoje.getDayOfYear());

// Criação de uma nova instância com alteração (imutável)
System.out.println("Alterando mês: " + hoje.withMonth(2) + ", Alterando ano: " + hoje.withYear(2019));
// Adição
System.out.println("Amanhã: " + hoje.plusDays(1) + ", Próxima semana: " + hoje.plusWeeks(1) + ", Próximo mês: " + hoje.plusMonths(1) + ", Próximo ano: " + hoje.plusYears(1));
// Subtração
System.out.println("Ontem: " + hoje.minusDays(1) + ", Semana passada: " + hoje.minusWeeks(1) + ", Mês passado: " + hoje.minusMonths(1) + ", Ano passado: " + hoje.minusYears(1));
// Cálculo de período entre datas usando 'until' ou Period.between()

java.time.LocalTime

LocalTime armazena apenas o tempo (hora, minuto, segundo, nanossegundo). Possui métodos análogos aos de LocalDate. Seu método until() e between() são convenientes para calcular a diferença entre dois horários.

LocalTime agora = LocalTime.now();
System.out.println("Formato padrão LocalTime: " + agora);
// Saída: "Formato padrão LocalTime: 17:50:24.438"

LocalTime manha = LocalTime.of(8, 20);
LocalTime tarde = LocalTime.of(17, 20, 45, 342123342);
LocalTime horarioParseado = LocalTime.parse("08:20", DateTimeFormatter.ISO_TIME);
LocalTime horarioDeData = LocalDateTime.now().toLocalTime();

LocalTime horarioCalculado = manha.plusMinutes(1).plusHours(40);
System.out.println("Diferença em minutos: " + horarioCalculado.until(manha, MINUTES));
System.out.println("Entre manha e horarioCalculado (min): " + MINUTES.between(manha, horarioCalculado) + " horas: " + horarioCalculado.until(manha, HOURS) + " meio-dias: " + horarioCalculado.until(manha, HALF_DAYS));

java.time.LocalDateTime

LocalDateTime combina as funcionalidades de LocalDate e LocalTime. Contém quase todos os métodos disponíveis nas classes anteriores e permite conversões fáceis para LocalDate e LocalTime. É a classe mais completa para manipulação de data e hora sem informação de fuso horário.

java.time.YearMonth

Útil para cenários onde apenas o ano e o mês são relevantes, como em relatórios mensais.

DateTimeFormatter formatador = DateTimeFormatter.ofPattern("yyyy-MM");
// Definir fuso horário
ZoneId fusoHorario = ZoneId.of("Asia/Shanghai");
String textoRelatorio = "2023-01";
YearMonth mesAtual = YearMonth.now(fusoHorario);
YearMonth mesRelatorio = YearMonth.parse(textoRelatorio, formatador);
if (mesRelatorio.isAfter(mesAtual)) {
    textoRelatorio = mesAtual.toString(); // Ajusta para o mês atual se o informado for futuro
}

Considerações Finais

Recomenda-se fortemente o uso das classes do pacote java.time (com prefixo Local) no Java 8 e superior, pois oferecem uma API mais robusta, intuitiva e segura, sendo todas imutáveis e, consequentemente, thread-safe.

Tags: java8 java.time localdate localtime LocalDateTime

Publicado em 7-2 06:33