W3docs

Java TemporalAdjusters

Compute dates relative to others in Java with TemporalAdjusters — firstDayOfMonth, next, previous.

Java TemporalAdjusters

plusDays(7) adds seven days. withDayOfMonth(15) jumps to the 15th. Those two cover the simple cases. A TemporalAdjuster is a function-shaped object you pass to Temporal.with(adjuster) to handle the cases where the new date depends on the current one in a more complicated way: "the first Monday of next month," "the last day of this quarter," "next year's American Thanksgiving."

The interface is one method:

@FunctionalInterface
interface TemporalAdjuster {
  Temporal adjustInto(Temporal temporal);
}

You don't usually implement it. The class java.time.temporal.TemporalAdjusters (note the sAdjusters, plural) is a kit of about a dozen built-in adjusters that cover the common cases, and LocalDate.with(adjuster) is how you apply them.

The built-in catalogue

Import statically; the code reads better that way:

import static java.time.temporal.TemporalAdjusters.*;

Then:

AdjusterEffect
firstDayOfMonth()day → first day of the same month
lastDayOfMonth()day → last day of the same month
firstDayOfNextMonth()day → first day of the next month
firstDayOfYear()day → January 1 of the same year
lastDayOfYear()day → December 31 of the same year
firstDayOfNextYear()day → January 1 of the next year
next(DayOfWeek dow)the next dow strictly after the date
nextOrSame(DayOfWeek dow)today if it's dow, otherwise next dow
previous(DayOfWeek dow)the most recent dow strictly before the date
previousOrSame(DayOfWeek dow)today if it's dow, otherwise previous dow
dayOfWeekInMonth(int ord, DayOfWeek dow)nth weekday of the month: dayOfWeekInMonth(3, MONDAY) → 3rd Monday
firstInMonth(DayOfWeek dow)first dow of the month (equivalent to dayOfWeekInMonth(1, dow))
lastInMonth(DayOfWeek dow)last dow of the month

The two halves answer "what's the first/last X" (top half) and "what's the next/previous X" (bottom half). Chain them when the question is more complex:

LocalDate firstMondayNextMonth = today.with(firstDayOfNextMonth()).with(nextOrSame(DayOfWeek.MONDAY));

That's "the first Monday on or after the first of next month." Read left to right; each with is a step.

Apply with 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 exists on every Temporal: LocalDate, LocalDateTime, ZonedDateTime, even OffsetDateTime. The adjuster only touches the date components — applying lastDayOfMonth() to a LocalDateTime leaves the time alone.

Adjusters are total: they always return a result. There's no "what if today isn't in the right month" exception path — lastDayOfMonth() from January 31 is still January 31 (the last day is itself).

Lambda adjusters

Because TemporalAdjuster is a @FunctionalInterface, you can write your own with a 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-10

The pattern: convert the incoming Temporal to the date type you want (LocalDate.from(t)), compute the new date, return it. The return type is Temporal (the interface), but the JDK accepts the concrete return.

For one-off use this is overkill — just inline the logic next to the call site. For a calculation you'll use in multiple places (next working day, last day of quarter, observed holiday), bundling it as an adjuster keeps the call sites readable.

ofDateAdjuster for the simple lambda case

If your adjuster works on LocalDate only (the common case), TemporalAdjusters.ofDateAdjuster(UnaryOperator<LocalDate>) is the cleaner factory:

TemporalAdjuster nextWorkingDay = TemporalAdjusters.ofDateAdjuster(d -> {
  LocalDate result = d.plusDays(1);
  while (result.getDayOfWeek().getValue() > 5) {
    result = result.plusDays(1);
  }
  return result;
});

The lambda takes and returns a LocalDate. The factory wraps it as a TemporalAdjuster. This is what you reach for 90% of the time when writing custom adjusters.

A worked example: business dates, holidays, end-of-period

The program below uses adjusters for the bookkeeping calendar: end-of-month for billing, last business day of the month for cash close, the first Monday of next month for a regular planning meeting, a holiday-aware "next working day" adjuster, and end-of-quarter computation.

java— editable, runs on the server

What to take from the run:

  • The built-in adjusters covered the boundary cases (firstDayOfMonth, lastDayOfMonth, firstDayOfYear, etc.) without any arithmetic on your side. For "this date snapped to the start/end of its month or year," they're the right tool — clearer than withDayOfMonth(1)-style by-hand computation, and immune to month-length surprises.
  • next(MONDAY) and previous(FRIDAY) returned strictly different dates; nextOrSame(TUESDAY) on a Tuesday returned today. Memorise the strict-vs-or-same distinction; it's the source of most "off by one week" bugs when the date you start from happens to fall on the target weekday.
  • The chained firstDayOfNextMonth().nextOrSame(MONDAY) expressed "the first Monday on or after the first of next month" in two reads. The chain is one line; the by-hand equivalent is six. Chaining adjusters is the idiomatic way to compose them.
  • NEXT_BUSINESS_DAY skipped the weekend and a holiday in one shot. The HOLIDAYS set was a synthetic two-element example; a real implementation would load from a service. The adjuster shape is the same — wrap the loop in TemporalAdjusters.ofDateAdjuster(...) and you can drop it into today.with(NEXT_BUSINESS_DAY) calls everywhere.
  • END_OF_QUARTER was a one-line custom adjuster that picked the third month of the date's quarter and applied lastDayOfMonth(). The point: complex domain operations belong in named TemporalAdjuster constants, where the call site reads someDate.with(END_OF_QUARTER) instead of inlining a six-line arithmetic block. Keep the calendar logic in one place.

What's next

TemporalAdjusters close out the modern java.time API. The last two chapters of this part cover the legacy types you'll meet in older code: Java Legacy Date Class for the original java.util.Date, and Java Calendar Class for java.util.Calendar. Both are still around for compatibility; both have a clean conversion path to java.time.

Practice

Practice

You need 'the first Monday of next month' starting from any given date. Which expression returns that value most idiomatically?