Java TemporalAdjusters
Calcule datas relativas em Java com TemporalAdjusters — firstDayOfMonth, next, previous.
plusDays(7) adiciona sete dias. withDayOfMonth(15) salta para o dia 15. Esses dois cobrem os casos simples. Um TemporalAdjuster é um objeto com formato de função que você passa para Temporal.with(adjuster) para lidar com os casos em que a nova data depende da data atual de forma mais complexa: "a primeira segunda-feira do próximo mês," "o último dia deste trimestre," "o Dia de Ação de Graças americano do próximo ano."
A interface tem um único método:
@FunctionalInterface
interface TemporalAdjuster {
Temporal adjustInto(Temporal temporal);
}Normalmente você não a implementa. A classe java.time.temporal.TemporalAdjusters (note o s — Adjusters, plural) é um kit com cerca de uma dúzia de ajustadores integrados que cobrem os casos comuns, e LocalDate.with(adjuster) é como você os aplica.
O catálogo integrado
Importe estaticamente; o código fica mais legível assim:
import static java.time.temporal.TemporalAdjusters.*;Em seguida:
| Ajustador | Efeito |
|---|---|
firstDayOfMonth() | dia → primeiro dia do mesmo mês |
lastDayOfMonth() | dia → último dia do mesmo mês |
firstDayOfNextMonth() | dia → primeiro dia do próximo mês |
firstDayOfYear() | dia → 1º de janeiro do mesmo ano |
lastDayOfYear() | dia → 31 de dezembro do mesmo ano |
firstDayOfNextYear() | dia → 1º de janeiro do próximo ano |
next(DayOfWeek dow) | o próximo dow estritamente após a data |
nextOrSame(DayOfWeek dow) | hoje se for dow, caso contrário o próximo dow |
previous(DayOfWeek dow) | o dow mais recente estritamente antes da data |
previousOrSame(DayOfWeek dow) | hoje se for dow, caso contrário o dow anterior |
dayOfWeekInMonth(int ord, DayOfWeek dow) | n-ésimo dia da semana do mês: dayOfWeekInMonth(3, MONDAY) → 3ª segunda-feira |
firstInMonth(DayOfWeek dow) | primeiro dow do mês (equivalente a dayOfWeekInMonth(1, dow)) |
lastInMonth(DayOfWeek dow) | último dow do mês |
As duas metades respondem "qual é o primeiro/último X" (metade superior) e "qual é o próximo/anterior X" (metade inferior). Encadeie-os quando a questão for mais complexa:
LocalDate firstMondayNextMonth = today.with(firstDayOfNextMonth()).with(nextOrSame(DayOfWeek.MONDAY));Isso significa "a primeira segunda-feira em ou após o primeiro dia do próximo mês." Leia da esquerda para a direita; cada with é um passo.
Aplicar com with(adjuster)
LocalDate today = LocalDate.now();
LocalDate eom = today.with(lastDayOfMonth());
LocalDate nextMonday = today.with(next(DayOfWeek.MONDAY));
LocalDate thirdFriday = today.with(dayOfWeekInMonth(3, DayOfWeek.FRIDAY));with existe em todo Temporal: LocalDate, LocalDateTime, ZonedDateTime, até OffsetDateTime. O ajustador toca apenas os componentes de data — aplicar lastDayOfMonth() a um LocalDateTime deixa o horário intacto.
Os ajustadores são totais: sempre retornam um resultado. Não há caminho de exceção "e se hoje não estiver no mês certo" — lastDayOfMonth() a partir de 31 de janeiro ainda é 31 de janeiro (o último dia é ele mesmo).
Ajustadores lambda
Como TemporalAdjuster é uma @FunctionalInterface, você pode escrever o seu próprio com uma lambda:
TemporalAdjuster nextWorkingDay = t -> {
LocalDate d = LocalDate.from(t).plusDays(1);
while (d.getDayOfWeek() == DayOfWeek.SATURDAY || d.getDayOfWeek() == DayOfWeek.SUNDAY) {
d = d.plusDays(1);
}
return d;
};
LocalDate friday = LocalDate.of(2025, 11, 7);
LocalDate monday = friday.with(nextWorkingDay); // 2025-11-10O padrão: converta o Temporal recebido para o tipo de data desejado (LocalDate.from(t)), calcule a nova data, retorne-a. O tipo de retorno é Temporal (a interface), mas o JDK aceita o retorno concreto.
Para uso pontual, isso é exagero — basta embutir a lógica próxima ao local da chamada. Para um cálculo que você usará em vários lugares (próximo dia útil, último dia do trimestre, feriado observado), encapsulá-lo como um ajustador mantém os locais de chamada legíveis.
ofDateAdjuster para o caso lambda simples
Se o seu ajustador funciona apenas com LocalDate (o caso comum), TemporalAdjusters.ofDateAdjuster(UnaryOperator<LocalDate>) é a fábrica mais limpa:
TemporalAdjuster nextWorkingDay = TemporalAdjusters.ofDateAdjuster(d -> {
LocalDate result = d.plusDays(1);
while (result.getDayOfWeek().getValue() > 5) {
result = result.plusDays(1);
}
return result;
});A lambda recebe e retorna um LocalDate. A fábrica o encapsula como um TemporalAdjuster. É isso que você usa em 90% das vezes ao escrever ajustadores personalizados.
Um exemplo trabalhado: datas comerciais, feriados, fim de período
O programa abaixo usa ajustadores para o calendário contábil: fim de mês para faturamento, último dia útil do mês para fechamento de caixa, a primeira segunda-feira do próximo mês para uma reunião regular de planejamento, um ajustador "próximo dia útil" com consciência de feriados, e cálculo de fim de trimestre.
O que observar na execução:
- Os ajustadores integrados cobriram os casos de limite (
firstDayOfMonth,lastDayOfMonth,firstDayOfYear, etc.) sem nenhuma aritmética da sua parte. Para "esta data ajustada ao início/fim do seu mês ou ano," eles são a ferramenta certa — mais claros do que computações manuais no estilowithDayOfMonth(1), e imunes a surpresas com o comprimento do mês. next(MONDAY)eprevious(FRIDAY)retornaram datas estritamente diferentes;nextOrSame(TUESDAY)em uma terça-feira retornou hoje. Memorize a distinção estrito-vs-ou-mesmo; ela é a fonte da maioria dos bugs de "uma semana de diferença" quando a data de início cai no dia da semana alvo.- O encadeamento
firstDayOfNextMonth().nextOrSame(MONDAY)expressou "a primeira segunda-feira em ou após o primeiro dia do próximo mês" em duas leituras. O encadeamento é uma linha; o equivalente manual são seis. Encadear ajustadores é a forma idiomática de compô-los. NEXT_BUSINESS_DAYpulou o fim de semana e um feriado de uma vez. O conjuntoHOLIDAYSfoi um exemplo sintético de dois elementos; uma implementação real carregaria a partir de um serviço. A forma do ajustador é a mesma — envolva o laço emTemporalAdjusters.ofDateAdjuster(...)e você pode usartoday.with(NEXT_BUSINESS_DAY)em qualquer lugar.END_OF_QUARTERfoi um ajustador personalizado de uma linha que selecionou o terceiro mês do trimestre da data e aplicoulastDayOfMonth(). O ponto: operações de domínio complexas pertencem a constantes nomeadasTemporalAdjuster, onde o local de chamada lêsomeDate.with(END_OF_QUARTER)em vez de embutir um bloco aritmético de seis linhas. Mantenha a lógica do calendário em um único lugar.
O que vem a seguir
TemporalAdjusters encerram a API moderna java.time. Os dois últimos capítulos desta parte cobrem os tipos legados que você encontrará em código mais antigo: Java Legacy Date Class para o java.util.Date original, e Java Calendar Class para java.util.Calendar. Ambos ainda existem por compatibilidade; ambos têm um caminho de conversão limpo para java.time.