Huigege Huigege - 2 months ago 11
Android Question

Compare Date using GregorianCalendar

I'm trying to compare the current date(2016-08-31) with given date (2016-08-31).
My current mobile device time zone is GMT-08:00 Pacific Time.

If I disable automatic date & time zone on device and set time zone as GMT+08:00 Perth, method1 will return true but method2 returns false;

The result of method2 is expected since I compare the date without time zone, so "2016-08-31" before "2016-08-31" is false; Why method1 returns true?

public boolean method1() {
try {
GregorianCalendar currentCalendar = new GregorianCalendar();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date endDate = sdf.parse("2016-08-31");
Calendar endCalendar = new GregorianCalendar();
endCalendar.setTime(endDate);

if (endCalendar.before(currentCalendar)) {
return true;
} else {
return false;
}
} catch (ParseException e) {
...
}
}


public boolean method2() {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date currentDate = sdf.parse(formatter.format(new Date()));
Date endDate = sdf.parse("2016-08-31");

if (endDate.before(currentDate)) {
return true;
} else {
return false;
}

} catch (ParseException e) {
...
}
}

Answer

With and without time zone

Likely explanation: Your code mixes use of zoned and UTC date-time objects. In some lines, you have an object assigned a time zone (java.util.Calendar), your JVM’s current default time zone. In other lines you have an object (java.util.Date) fixed in UTC. The Australia/Perth time zone is 8 hours ahead of UTC, so of course you can see a difference in dates. Printing out their milliseconds-since-epoch number would make obvious the comparison results.

Do yourself a big favor: Avoid these notoriously troublesome old classes. Use java.time instead.

Boolean isFuture = 
    LocalDate.parse( "2016-08-31" )
             .isAfter( LocalDate.now( ZoneId.of( "Australia/Perth" ) ) ) ;

Using java.time

You are using troublesome old legacy date-time classes, now supplanted by the java.time classes.

Getting the current date requires a time zone. For any given moment, the date varies around the globe by zone. If omitted, your JVM’s current default time zone is implicitly applied. Better to specify, as that default can change at any moment.

Specify a proper time zone name. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "Australia/Perth" ) ;

The LocalDate class represents a date-only value without time-of-day and without time zone.

LocalDate today = LocalDate.now( z );

Your input string happens to comply with standard ISO 8601 formats. So parse directly with LocalDate. No need to specify formatting pattern.

LocalDate ld = LocalDate.parse( "2016-08-31" );

Compare with isBefore, isAfter, isEqual, and compareTo.

Boolean isFuture = ld.isAfter( today );

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to java.time.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.

Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.