Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LocalDate minus a Period get wrong result

LocalDate minus a Period(like "28 years, 1 months and 27 days"),get wrong result.

But minus a Period(only have days unit ,like "10282"days) get right result. Is there anything to notice?

public static void main(String[] args) {
    printAgeAndBirthday(1989, 2, 22);

    printBirthdayFromPeriod(28, 1, 27);
}
  private static void printBirthdayFromPeriod(int years, int months, int days) {
    final Period period = Period.of(years, months, days);
    final LocalDate now = LocalDate.now();
    final LocalDate birthday = now.minus(28, ChronoUnit.YEARS)
            .minus(1, ChronoUnit.MONTHS)
            .minus(27, ChronoUnit.DAYS);

    System.out.println("your birthday is : "+ birthday);//1989-02-19
    System.out.println("your birthday is : "+ now.minusYears(28).minusMonths(1).minusDays(27));//1989-02-19
    System.out.println("your birthday is : "+ now.minus(period));//1989-02-19
    System.out.println("your birthday is : "+period.subtractFrom(now));//1989-02-19
    System.out.println("your birthday is : "+ now.minus(Period.ofDays(10282)));//1989-02-22
}

private static void printAgeAndBirthday(int year, int month, int dayOfMonth) {
    LocalDate today = LocalDate.now();
    LocalDate birthday = LocalDate.of(year, month, dayOfMonth);

    Period p = Period.between(birthday, today);
    long p2 = ChronoUnit.DAYS.between(birthday, today);
    System.out.printf("You are %d years, %d months, and %d days old. (%d days total)%n",
            p.getYears(), p.getMonths(), p.getDays(), p2);

    LocalDate nextBDay = birthday.withYear(today.getYear());

    //If your birthday has occurred this year already, add 1 to the year.
    if (nextBDay.isBefore(today) || nextBDay.isEqual(today)) {
        nextBDay = nextBDay.plusYears(1);
    }

    Period p_1 = Period.between(today, nextBDay);
    long p_2 = ChronoUnit.DAYS.between(today, nextBDay);
    System.out.printf("There are %d months, and %d days until your next birthday. (%d total)%n",
            p_1.getMonths(), p_1.getDays(), p_2);
}

the console log:

You are 28 years, 1 months, and 27 days old. (10282 days total)
There are 10 months, and 4 days until your next birthday. (310 total)
your birthday is : 1989-02-19
your birthday is : 1989-02-19
your birthday is : 1989-02-19
your birthday is : 1989-02-19
your birthday is : 1989-02-22

java version : jdk1.8.0_45

like image 827
ChouChou Avatar asked Apr 18 '17 11:04

ChouChou


People also ask

How do you subtract LocalDate?

LocalDate minus() method in Java An immutable copy of a LocalDate where the required duration is subtracted from it can be obtained using the minus() method in the LocalDate class in Java. This method requires two parameters i.e. the duration to be subtracted and the TemporalUnit of the duration.

Does LocalDate store time?

LocalDate doesn't store hours, just year, month of year and day of month.

Which of the static function of LocalDate return current date?

now() now() method of a LocalDate class used to obtain the current date from the system clock in the default time-zone. This method will return LocalDate based on system clock with default time-zone to obtain the current date.

How do I set a month in LocalDate?

The withMonth() method of LocalDate class in Java returns a copy of this LocalDate with the month-of-year altered. Parameter: This method accepts a mandatory parameter month which specifies the month-of-year to set in the result, from 1 i.e., January to 12 i.e., December.


1 Answers

Your case can be simplified to

LocalDate date1 = LocalDate.of(2017, 2, 22), date2 = LocalDate.of(2017, 4, 18);
Period p = Period.between(date1, date2);
System.out.println("date1 + p: "+date1.plus(p));
System.out.println("date2 - p: "+date2.minus(p));

which will print

date1 + p: 2017-04-18
date2 - p: 2017-02-19

In other words, the number of years is irrelevant (unless one of the years involved is a leap year and the other isn’t, but here, both aren’t). The following illustrates the issue:

February                       March                                                                                        April
19 20 21 22 23 24 25 26 27 28  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18
 ↑        │                                                                                   ↑                                                                                ↑
 │        └──────────────────────────── plus one Month ───────────────────────────────────────┴───────────────────────── plus 27 days ─────────────────────────────────────────┤
 │                                                                                ↑                                                                                            ↓
 └───────────────────────── minus 27 days ────────────────────────────────────────┴─────────────────── minus one month ────────────────────────────────────────────────────────┘

This will change, if you swap the direction:

Period p2 = Period.between(date2, date1);
System.out.println("date1 - p2: "+date1.minus(p2));
System.out.println("date2 + p2: "+date2.plus(p2));

which will print

date1 - p2: 2017-04-15
date2 + p2: 2017-02-22

So when you express a period in terms of years, month and days, the direction becomes relevant. In contrast, the plain number of days between two dates is invariant:

LocalDate date1 = LocalDate.of(2017, 2, 22), date2 = LocalDate.of(2017, 4, 18);
Period p = Period.ofDays((int)ChronoUnit.DAYS.between(date1, date2));
System.out.println("date1 + p: "+date1.plus(p));
System.out.println("date2 - p: "+date2.minus(p));
date1 + p: 2017-04-18
date2 - p: 2017-02-22
like image 91
Holger Avatar answered Sep 19 '22 00:09

Holger