We add days to a date in Java with plusDays(n) on a LocalDate and subtract them with minusDays(n), and the same pairs of methods exist for weeks, months and years. Each call returns a new date and leaves the original unchanged, because the java.time classes are immutable.
We use these methods for due dates, trial periods, renewal dates, retention windows and any “30 days from today” rule in an app. They work the same way on LocalDateTime and ZonedDateTime.
The following example starts from an invoice dated January 31, 2026 and moves it in every direction.
LocalDate invoiceDate = LocalDate.of(2026, 1, 31);
LocalDate dueDate = invoiceDate.plusDays(30); // 2026-03-02
LocalDate weekBefore = invoiceDate.minusWeeks(1); // 2026-01-24
LocalDate nextMonth = invoiceDate.plusMonths(1); // 2026-02-28
LocalDate lastYear = invoiceDate.minusYears(1); // 2025-01-31
LocalDate mixed = invoiceDate.plus(Period.of(1, 2, 3)); // 2027-04-03
Notice that January 31 plus one month gives February 28, not March 3. That month-end rule, leap years, daylight saving time and the conversion from an old java.util.Date are the parts that surprise people, so each one gets its own section after the method overview.
1. The plusX() and minusX() Methods
The LocalDate class has one plus method and one minus method for each calendar unit. All of them take a long, so a negative number moves in the other direction, and plusDays(-5) gives the same result as minusDays(5).
| Unit | Add | Subtract | Example on 2026-01-31 |
|---|---|---|---|
| Days | plusDays(n) | minusDays(n) | plusDays(1) gives 2026-02-01 |
| Weeks | plusWeeks(n) | minusWeeks(n) | plusWeeks(2) gives 2026-02-14 |
| Months | plusMonths(n) | minusMonths(n) | plusMonths(1) gives 2026-02-28 |
| Years | plusYears(n) | minusYears(n) | plusYears(1) gives 2027-01-31 |
| Any unit | plus(n, ChronoUnit.X) | minus(n, ChronoUnit.X) | plus(1, ChronoUnit.DECADES) gives 2036-01-31 |
The methods return a new object, so a call whose result we do not assign changes nothing. This is a common bug in date code that moved from Calendar, where add() changed the object itself.
LocalDate start = LocalDate.of(2026, 5, 10);
start.plusDays(5); // result ignored, start is still 2026-05-10
LocalDate end = start.plusDays(5); // 2026-05-15
LocalDate back = start.plusDays(-5); // 2026-05-05
A result outside the supported range of years (-999,999,999 to 999,999,999) throws a DateTimeException. Ordinary business dates never get near it, but code that adds user input to LocalDate.MAX as a “no end date” marker can hit it.
LocalDate overflow = LocalDate.MAX.plusDays(1); // DateTimeException: Invalid value for Year
2. Adding Days and Months with ChronoUnit and Period
When the unit comes from configuration or user input, the generic plus(amount, unit) method is more convenient than picking the right plusX() method in an if chain. The unit is a ChronoUnit constant such as DAYS, WEEKS, MONTHS or YEARS.
LocalDate signup = LocalDate.of(2026, 4, 15);
LocalDate trialEnd = signup.plus(14, ChronoUnit.DAYS); // 2026-04-29
LocalDate review = signup.plus(6, ChronoUnit.MONTHS); // 2026-10-15
LocalDate archive = signup.minus(2, ChronoUnit.YEARS); // 2024-04-15
A Period holds an amount in years, months and days, so one object can say “1 month and 10 days”. It is useful when the rule is stored as text, for example in application.properties, because Period.parse() reads the ISO-8601 format such as P1M10D. The Period article covers the class in detail.
Period gracePeriod = Period.parse("P1M10D"); // P1M10D
LocalDate expiry = LocalDate.of(2026, 4, 15).plus(gracePeriod); // 2026-05-25
LocalDate before = LocalDate.of(2026, 4, 15).minus(gracePeriod); // 2026-03-05
A Period adds the years first, the months second and the days last. That order matters near the end of a month, as the next section shows.
3. What Happens at the End of a Month
Adding months or years keeps the day of the month when the target month has that day. When it does not, plusMonths() uses the last valid day of the target month instead of throwing an exception or spilling into the next month. The same rule makes February 29 plus one year land on February 28.

LocalDate jan31 = LocalDate.of(2026, 1, 31);
LocalDate feb = jan31.plusMonths(1); // 2026-02-28
LocalDate roundTrip = feb.minusMonths(1); // 2026-01-28, not January 31
LocalDate leapDay = LocalDate.of(2028, 2, 29);
LocalDate nextYear = leapDay.plusYears(1); // 2029-02-28
LocalDate fourYears = leapDay.plusYears(4); // 2032-02-29
Because one step loses information, the order of chained calls changes the result. Adding a month to January 30 and a day after that gives March 1, whereas adding the day first gives January 31, and the month after that is clamped to February 28.
LocalDate jan30 = LocalDate.of(2026, 1, 30);
LocalDate monthFirst = jan30.plusMonths(1).plusDays(1); // 2026-03-01
LocalDate dayFirst = jan30.plusDays(1).plusMonths(1); // 2026-02-28
3.1. Monthly Billing Dates from an Anchor Date
Say a subscription app bills a customer who signed up on January 31. A loop that adds one month to the previous billing date drifts, because after February 28 every later date stays on the 28th. Computing every billing date from the original sign-up date keeps the customer on the last day of each month.
static LocalDate billingDate(LocalDate signup, int cycle) {
return signup.plusMonths(cycle); // always from the anchor date
}
LocalDate signupDay = LocalDate.of(2026, 1, 31);
LocalDate second = billingDate(signupDay, 1); // 2026-02-28
LocalDate third = billingDate(signupDay, 2); // 2026-03-31
LocalDate drifted = signupDay.plusMonths(1).plusMonths(1); // 2026-03-28
When a rule says “30 days”, we use plusDays(30), and when it says “one month”, we use plusMonths(1). The two give different dates in most months, so the business rule decides, not the code.
4. Adding Days to LocalDateTime and ZonedDateTime
The LocalDateTime class has the same methods and keeps the time of day. It has no time zone, so one day is always the same clock time on the next date.
LocalDateTime meeting = LocalDateTime.of(2026, 1, 31, 14, 30);
LocalDateTime followUp = meeting.plusDays(7); // 2026-02-07T14:30
LocalDateTime nextMonthSlot = meeting.plusMonths(1); // 2026-02-28T14:30
A ZonedDateTime also keeps the local clock time when we add days, months or years, even across a daylight saving change. In New York, clocks moved forward on March 8, 2026, so 9:00 on March 7 plus one day is 9:00 on March 8, which is only 23 hours later.
ZonedDateTime standup = ZonedDateTime.of(2026, 3, 7, 9, 0, 0, 0, ZoneId.of("America/New_York"));
ZonedDateTime nextStandup = standup.plusDays(1); // 2026-03-08T09:00-04:00[America/New_York]
Duration elapsed = Duration.between(standup, nextStandup); // PT23H
That behavior is what a calendar app wants, because a daily meeting stays at 9:00. When we need an exact number of hours instead, we add hours or a Duration, as the hours, minutes and seconds article shows.
5. Adding Days to a java.util.Date
Old APIs such as JDBC drivers, JAXB classes or a library we cannot change still hand us a java.util.Date. We convert it to a LocalDate in an explicit time zone, add the days with java.time, and convert back at the edge of our code. The zone matters, because a Date is an instant and its calendar date differs between zones.
Date legacy = Date.from(Instant.parse("2026-01-31T10:00:00Z"));
ZoneId zone = ZoneId.of("Europe/Paris");
LocalDate asDate = legacy.toInstant().atZone(zone).toLocalDate(); // 2026-01-31
LocalDate plusTen = asDate.plusDays(10); // 2026-02-10
Date backToLegacy = Date.from(plusTen.atStartOfDay(zone).toInstant());
Instant stored = backToLegacy.toInstant(); // 2026-02-09T23:00:00Z
The last line shows midnight in Paris as 23:00 UTC of the previous day, which is correct. For a java.sql.Date, the methods toLocalDate() and java.sql.Date.valueOf(LocalDate) skip the time zone step, as the LocalDate to Date conversion article explains.
6. Add Days to a Date in Java FAQs
After the first plusDays() call, readers ask about the current date, months and business days next.
6.1. How do we add days to the current date in Java?
We call LocalDate.now() with an explicit zone and add to it. Without the zone argument, the JVM default zone decides what “today” is, which differs between a laptop and a server in UTC.
6.2. Is plusMonths(1) the same as plusDays(30)?
No. The method plusMonths(1) keeps the day of the month, so April 15 becomes May 15, whereas plusDays(30) gives May 15 only in 30-day months. For January 31, the two give February 28 and March 2.
6.3. How do we add only business days to a date?
The JDK has no business-day method, because weekends and holidays differ by country. We loop with plusDays(1) and skip Saturdays, Sundays and holidays, as shown in add or subtract business days.
6.4. Does plusDays() change the original LocalDate?
No. Every java.time date class is immutable, so plusDays() returns a new object and we must assign it. The same rule makes the classes safe to share between threads.
6.5. How do we find the number of days between two dates after adding days?
We use ChronoUnit.DAYS.between(start, end), which returns a long. The days between dates article covers it with time zones and Period.
7. Conclusion
The plusDays(), plusWeeks(), plusMonths() and plusYears() methods and their minus twins return a new date, and plus(n, unit) or a Period covers amounts that come from configuration.
Month and year arithmetic moves to the last valid day of a short month, so it cannot always be reversed, and recurring dates are safer when we compute them from an anchor date. On a ZonedDateTime, adding days keeps the clock time across daylight saving changes. The Java date and time guide also covers comparing dates and counting the days between them.
8. References
- LocalDate (Java SE 25 API)
- Period (Java SE 25 API)
- ChronoUnit (Java SE 25 API)
- ZonedDateTime (Java SE 25 API)
Happy Learning !!
Thanks, it worked for me. Continue your good deeds