How do I compare two Periods in java 8?
E.g.
Period one = Period.of(10,0,0);
Period two = Period.of(8,0,0);
here in this case one is greater than two.
It is true that the comparison of two Period
objects does not make sense in a general case, due to the undefined standard length of a month.
However, in many situations you can quite well live with an implementation similar to that which follows. The contract will be similar to the contract of compareTo()
:
public int comparePeriodsApproximately(Period p1, Period p2) {
return period2Days(p1) - period2Days(p2);
}
private int period2Days(Period p) {
if (p == null) {
return 0;
}
return (p.getYears() * 12 + p.getMonths()) * 30 + p.getDays();
}
This one should be bullet-proof. Whether it’s useful?
I claim that you get the smallest possible amount of days from a given number of years and months by counting forward from February 1, 2097 since you are first counting February (28 days) and it takes a long time until you get two months with 31 days in a row (July and August) and still longer until you hit a leap year (2104). Also 2200 and 2300 are non-leap years, should the counting reach that far. Conversely you get the greatest possible number of days when counting backward from the same date. You start by counting through 2 months @ 31 days (January and December). The first February you encounter is in 2096, a leap year, so 29 days. And 2000 is a leap year.
So my trick is to count the difference between the two periods both ways from the mentioned date. If counts agree that the difference is positive (or negative), then two
(or one
) will always be longer no matter which day we count from.
In some cases the counts will not agree. Then I refuse to call a longer period.
Period one = Period.of(10, 0, 0);
Period two = Period.of(8, 0, 0);
if (one.normalized().equals(two.normalized())) {
System.out.println("They are the same.");
} else {
Period diff = two.minus(one);
LocalDate anchor = LocalDate.of(2097, Month.FEBRUARY, 1);
LocalDate plusDiff = anchor.plus(diff);
LocalDate minusDiff = anchor.minus(diff);
if (plusDiff.isAfter(anchor) && minusDiff.isBefore(anchor)) {
System.out.println("Two is greater (unambiguously)");
} else if (plusDiff.isBefore(anchor) && minusDiff.isAfter(anchor)) {
System.out.println("One is greater (unambiguously)");
} else {
System.out.println("Cannot decide");
}
}
Output in this case (using the periods from the question):
One is greater (unambiguously)
The normalized
method I am using in the first comparison converts between years and months ensuring that the months are in the interval from -11 through +11 and have the same sign as the years (except if years are 0). This can be done unambiguously since there are always 12 months in a year.
You may be able to refine it to report that one period is longer than or equal to the other. For example if one
is a month and two
is 31 days, we know that two
is at least as long as one
, even though we can’t decide whether it’s also strictly longer.
In case you have a period of months
and period of years
you can do as follows:
Period periodOfMonths = Period.ofMonths(16);
Period periodOfYears = Period.ofYears(1);
// Check if period of months is ghreather that the period of years
System.out.println(periodOfMonths.toTotalMonths() > periodOfYears.toTotalMonths());
Rightly said by JB Nizet. You cannot compare Periods, as per java doc in Period class there is similar class to Period (Duration) available in java, you can use that depends on your business requirement.
"Durations and periods differ in their treatment of daylight savings time when added to ZonedDateTime. A Duration will add an exact number of seconds, thus a duration of one day is always exactly 24 hours. By contrast, a Period will add a conceptual day, trying to maintain the local time."