Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java plusMonths at month end: prevent renewal-date drift

Last updated: 5 Oct 20264 min read
tutorial
IntermediateBy AITrove Editorial

Adding one month to a date near month end can clamp the day, so repeated additions may differ from an addition anchored to the original date.

Keep the original recurrence rule

A contract signed on January 31 may intend the last day of every month. Repeatedly adding one month to the previous invoice date loses that intent after February clamps the day. Calculate each occurrence from the anchor month and a declared day policy instead.

The fixture shows January 31, 2024 plus one month becomes February 29; another plus one month becomes March 29. Directly adding two months to January 31 yields March 31. YearMonth.atEndOfMonth expresses an explicit last-day policy.

Make the policy testable

Some products want the 31st where it exists and the last day otherwise; others want the 29th after the first clamp. Either can be valid. The error is allowing the library's chained arithmetic to choose the policy without review.

Working program

Java
import java.time.LocalDate;
import java.time.YearMonth;

public class ContractRenewalAnchor {
    public static void main(String[] args) {
        LocalDate signed = LocalDate.of(2024, 1, 31);
        LocalDate chained = signed.plusMonths(1).plusMonths(1);
        LocalDate anchored = signed.plusMonths(2);
        LocalDate lastDayPolicy = YearMonth.from(signed).plusMonths(2).atEndOfMonth();
        System.out.println(signed.plusMonths(1));
        System.out.println(chained);
        System.out.println(anchored);
        System.out.println(lastDayPolicy);
    }
}

Output

Output
2024-02-29
2024-03-29
2024-03-31
2024-03-31

Cost and ownership

Each calculation uses fixed-size immutable dates. A billing scheduler should retain its anchor and recurrence rule rather than derive future dates solely from the last emitted date; otherwise a one-time clamp can permanently alter the sequence.

Common Mistakes

  • Do not assume repeated plusMonths preserves the original day of month.
  • Do not encode a last-day rule as an accidental side effect of clamping.
  • Do not model a renewal month as a fixed number of elapsed hours.

Read next

Java YearMonth.atEndOfMonth: calculate a month boundary without guessed days, Java LocalDate half-open ranges: define an exclusive end, Java Duration versus Period across a daylight-saving change, Java date and time: local schedules versus instants.

java
time
period-month-end-arithmetic
Storage details