tags:

views:

578

answers:

4

I am pulling dates out of an Oracle database. They are set on a java.util.Date field and they are in reality java.sql.Timestamp instances (which is a subclass of Java.util.Date). If I compare two of these timestamps from two different database records by calling after() on the first date and compare it to the second, I get the wrong answer when all parts of the date are the same except for the milliseconds.

All of the following should result in "true", however the second set of numbers does not:

firstDate  = 1/1/2000 12:00:20:00
secondDate = 1/1/2000 12:00:10:00
result = firstDate.after(secondDate);
result is TRUE <-- EXPECTED RESULT

firstDate  = 1/1/2000 12:00:00:10
secondDate = 1/1/2000 12:00:00:00
result = firstDate.after(secondDate);
result is FALSE <-- NOT EXPECTED, result should be TRUE 

I know nanos are stored separately from the Date instance in the Timestamp class and I am curious if this is the issue.

A: 

It looks like the problem you're having is that firstDate and secondDate are set to Java.util.Date objects but the JavaDoc for java.sql.Timestamp mentions that it is a composite of java.util.Date and a separate nanoseconds value.

This is why it is returning false when you are trying to compare the two. If you changed firstDate and secondDate over to actual Timestamp objects they should work.

Sam Merrell
A: 

Without the actual code this is a speculation, but I think one of your objects is java.util.Date and the other is java.sql.Timestamp you cannot really compare them, as the millis field in 'Timestamp' is truncated to a second and the remainder is stored in nanos field. It's really unfortunate that Timestamp is a subclass of Date. This definitely leads to a problem that you are experiencing.

EDIT.

One more possibility, is that your DB driver returns its own subclass of Timestamp. Because the class is not final it's quite possible that their implementation screwed up Timestamp's compare, not that it's particularly hard to do.

Alexander Pogrebnyak
They are both java.sql.Timestamp instances.
BestPractices
+3  A: 

You can compare them, but only by comparing millis. While it's quite ugly, it seems to work in all cases (regardless of which is java.sql.Timestamp or java.util.Date).

if(date1.getTime() > date2.getTime()) {
  //...
}
Konrad Garus
+2  A: 

The key to the problem here is when the Timestamps are cast up to Date objects. The after method of Date is being used instead of the after method in Timestamp. When not cast to Date, the after method of Timestamp will work correctly.

I guess I need a lesson now on covariant method parameters as to why the after method in Timestamp isn't called in the following code.

    java.sql.Timestamp one = new java.sql.Timestamp(1266873627200L);
    java.sql.Timestamp two = new java.sql.Timestamp(1266873627000L);

    java.util.Date oneDate = (java.util.Date) one;
    java.util.Date twoDate = (java.util.Date) two;


    System.out.println("one: " + oneDate.getTime());
    System.out.println("two: " + twoDate.getTime());

    if (oneDate.after(twoDate)) {
        System.out.println(oneDate.getTime() + " after " + twoDate.getTime());
    } else {
        System.out.println(twoDate.getTime() + " after " + oneDate.getTime());
    }

results

one: 1266873627200
two: 1266873627000
1266873627000 after 1266873627200
s_t_e_v_e