LocalDate.plus Incorrect Answer
Asked Answered
H

2

18

Java's LocalDate API seems to be giving the incorrect answer when calling plus(...) with a long Period, where I'm getting an off by one error. Am I doing something wrong here?

import java.time.LocalDate;
import java.time.Month;
import java.time.Period;
import java.time.temporal.ChronoUnit;

public class Main
{
    public static void main(String[] args)
    {
        // Long Period
        LocalDate birthA = LocalDate.of(1965, Month.SEPTEMBER, 27);
        LocalDate eventA = LocalDate.of(1992, Month.MAY, 9);
        LocalDate halfA = eventA.plus(Period.between(birthA, eventA));
        System.out.println(halfA); // 2018-12-21 ????
        System.out.println(ChronoUnit.DAYS.between(birthA, eventA)); // 9721
        System.out.println(ChronoUnit.DAYS.between(eventA, halfA)); // 9722 ????

        // Short Period
        LocalDate birthB = LocalDate.of(2012, Month.SEPTEMBER, 10);
        LocalDate eventB = LocalDate.of(2012, Month.SEPTEMBER, 12);
        LocalDate halfB = eventB.plus(Period.between(birthB, eventB));
        System.out.println(halfB); // 2018-09-14
        System.out.println(ChronoUnit.DAYS.between(birthB, eventB)); // 2
        System.out.println(ChronoUnit.DAYS.between(eventB, halfB)); // 2
    }
}
Hospodar answered 10/5, 2019 at 15:19 Comment(0)
U
21

A Period is made of a number of years, months and days. In your case, Period.between(birthA, eventA) is 26 years, 7 months and 12 days.

If you add that to birthA, you get:

  • 1965 + 26 years -> 1991
  • September 1991 + 7 months -> April 1991
  • April 27, 1991 + 12 days -> May 9, 1992

Which works as expected.

If you apply the same calculation, starting from May 9, 1992, you get December 21, 2018.

If you want to add a certain number of days instead, you can't simply add the period (as years and months don't always have the same length). One option is to use ChonoUnit.DAYS.between instead:

LocalDate halfA = eventA.plusDays(ChronoUnit.DAYS.between(birthA, eventA));

That returns 2018-12-20 which I think is what you expected.

Untouched answered 10/5, 2019 at 15:31 Comment(1)
Ah, this made me finally understand what Period really is!Dunnock
E
7

To complement assylias' answer, here is a simplified example to show why this happens:

    public static void main(String[] args)
    {
        LocalDate a = LocalDate.of(1992, Month.APRIL, 1);
        LocalDate b = LocalDate.of(1992, Month.MAY, 1);
        // Calculate the period. It will return "One month"
        Period period = Period.between(a, b);
        // Add one month to b. It will return June 1, 1992
        LocalDate c = b.plus(period);
        System.out.println(ChronoUnit.DAYS.between(a, b)); // 30 days as April has 30 days
        System.out.println(ChronoUnit.DAYS.between(b, c)); // 31 days as May has 31 days
    }
Emphysema answered 10/5, 2019 at 15:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.