ponder275
ponder275

Reputation: 935

Why is the Calendar before() method returning true for equal dates

I am setting a color field based on how the dueDate field compares to the current date. dueDate is an SQL Date type. My problem is when I pass in the current date the Calendar.before() method says the date is before the current date. My code is:

private String getDateDueColor(Date dateDue) {
      Calendar today =  Calendar.getInstance();
      today.setTime(new java.sql.Date(Calendar.getInstance().getTime().getTime()));
      Calendar dueDate = Calendar.getInstance();
      dueDate.setTime(dateDue);
      if(dueDate.before(today)){
        return RED;
      }else{
        return NORMAL;
      }
  }

I have set a breakpoint and compared dueDate and today and all of the information in the cdate field for each object looks identical, but the dueDate.before(today) still returns true. Any help would be appreciated!

Upvotes: 0

Views: 7390

Answers (3)

Szymon Franz
Szymon Franz

Reputation: 1

Another way is to compare yyyy, mm, dd fields. If they are the same - dont use .after() nor .before() Simon Franz

Upvotes: 0

Basil Bourque
Basil Bourque

Reputation: 338574

The answer by marcospereira is correct. I'll add some general suggestions about revamping the code shown in the Question, and show the use of java.time.

Use java.sql only for database transfer

Do not pass around java.sql types and perform business logic on them. Use java.sql only for transferring data in and out of the database. For java.sql.Timestamp/.Date/.Time immediately convert them to java.time objects. Then proceed with your business logic.

LocalDate due = myJavaSqlDate.toLocalDate();

Avoid old date-time classes

Avoid the old date-time classes bundled with the earliest versions of Java such as java.util.Date/.Calendar. They are confusing, poorly designed, and troublesome.

java.time

In Java 8 and later, the old date-time class have been supplanted by the java.time framework. These new classes are a vast improvement. Inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project.

Date-only Value

The code in the Question suggests that you want to work with date-only values such as java.sql.Date pretends to be. Yet you mix it with java.util.Calendar which represents a date and a time-of-day.

Above in this Answer you can the java.time.LocalDate class. This class represents a date-only value without time-of-day nor time zone.

Time Zone

Time zone is crucial when dealing with date-only values. A date-only (without time-of-day) is inherently ambiguous. The date is not the same around the world at any given moment. A new day dawns earlier in the east. Minutes after midnight in Paris is still “yesterday” in Montréal.

So to determine “today” requires a time zone. If not specified, your JVM’s current default time zone is implicitly applied. Not good. Results may vary at runtime depending on settings of the host operating system and of the JVM. The default time zone can even be changed during runtime by any code in any thread of any app within the JVM.

So, better to specify the desired/expected time zone explicitly.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );

Now compare to see if the due date has passed.

if( today.isAfter( due ) ) {
    // Overdue.
}

Upvotes: 1

marcospereira
marcospereira

Reputation: 12214

Are you sure they are equal? Method equals for Date and Calendar means they represents the same time value (millisecond offset from the Epoch). See the javadocs for Calendar.equals method:

Compares this Calendar to the specified Object. The result is true if and only if the argument is a Calendar object of the same calendar system that represents the same time value (millisecond offset from the Epoch) under the same Calendar parameters as this object.

The before method docs states that compareTo is used to decide if a calendar instance is before another. And again, compareTo is using millisecond precision. From the docs:

Compares the time values (millisecond offsets from the Epoch) represented by two Calendar objects.

The alternatives are:

  1. If you have to use Calendar, create new instances, use clear method on them and then set values (year, month, hourOfDay, minute, second) using the set method.
  2. Use the new java.time API and choose some type that better represents what you want (maybe java.time.LocalDate)
  3. Use Joda Time if you can't go to Java 8.

Upvotes: 4

Related Questions