Comparing Dates in Java 7 using Calendar

2019-08-24 07:48发布

问题:

I am comparing the start Date of a treatement to its End to check if it lasts more than 6 months. If the period doesn't include the month of February all is good but if I compare the 1st of January to the 30th of June, it throws my Exception. To compare both periods I add 6 months to the start Date and compare the result to the end Date like so:

Date start = new Date(2017,1,1);
Date end = new Date(2017,6,30);

Calendar startOfTreatment = new Calendar.getInstance();
startOfTreatment.setTime(start);

Calendar endOfTreatment = new Calendar.getInstance();
endOfTreatment.setTime(end);

startOfTreatment.add(Calendar.MONTH, 6);
if (startOfTreatment.compareTo(endOfTreatment) > 0) {
    throw new InfinishedTreatmentException(startOfTreatment,endOfTreatment);
}

How can I fix this?

回答1:

The Date constructors (like the one you're using: new Date(2017,1,1)) are not only deprecated (so you should avoid them) but also misleading, because years are indexed at 1900 (so 2017 becomes 3917) and months are zero-indexed (the values are in the range zero (January) to 11 (December)). So this doesn't behave as you think:

Date start = new Date(2017, 1, 1); // February 1st 3917
Date end = new Date(2017, 6, 30); // July 30th 3917

When you add 6 months to start, it becomes August 1st, which is after end.

To create January 1st and June 30th you must use month - 1 and to have the year 2017 you must use 117 (2017 - 1900):

Date start = new Date(117, 0, 1); // January 1st 2017
Date end = new Date(117, 5, 30); // June 30th 2017

Even though, start plus 6 months will be July 1st, which still is after end (so your code will throw the exception).


The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.

In Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes.

This new API has lots of new date and time types to deal with different situations. As we're dealing only with dates (day/month/year), we can use a org.threeten.bp.LocalDate:

LocalDate start = LocalDate.of(2017, 1, 1); // January 1st 2017
LocalDate end = LocalDate.of(2017, 6, 30); // June 30th 2017

// 6 months after start
LocalDate sixMonthsLater = start.plusMonths(6);
if (sixMonthsLater.isAfter(end)) {
    // throw exception
}