5

Following a bug, I've noticed that if I create a java.sql.Timestamp from a java.util.Date, using the constructor that takes the milliseconds, the Date instance is always after() the Timestamp. This is puzzling, since (a) the contract for before() specifies a strict comparison and (b) if not equal, the Timestamp, because it has nanoseconds, might itself be after() the Date. But the results are opposite and repeatable (with JDK 1.6 and 1.7, with different JVM timezones). Comparing two Dates works correctly, but calling before() or after() on a Date and giving a Timestamp argument has unexpected results.

The sample code below has two Date and one Timestamp instance, all of them with the same millisecond value. Yet comparing a Date with a Timestamp shows the Date to be after() the Timestamp.

import java.util.Date;
import java.sql.Timestamp;

public class X extends Date {

    public static void main(String[] args) {
        Date d1 = new Date();
        Date d2 = new Date(d1.getTime());
        Timestamp t = new Timestamp (d1.getTime());
        System.out.println ("date1 = " + d1 + " (" + d1.getTime() + ")" );
        System.out.println ("date2 = " + d2 + " (" + d2.getTime() + ")" );
        System.out.println ("timestamp = " + t + "  (" + t.getTime() + ")" );
        System.out.println ("d1 before d2: " + d1.before(d2));
        System.out.println ("d1 after  d2: " + d1.after(d2));
        System.out.println ("d1 before ts: " + d1.before(t));
        System.out.println ("d1 after  ts: " + d1.after(t)); //why true?
    }
}

Sample output:

C:\>\Java\jdk1.7.0_05\bin\java X
date1 = Tue Oct 30 10:15:59 EDT 2012 (1351606559812)
date2 = Tue Oct 30 10:15:59 EDT 2012 (1351606559812)
timestamp = 2012-10-30 10:15:59.812  (1351606559812)
d1 before d2: false
d1 after  d2: false
d1 before ts: false
d1 after  ts: true

The last line is the curious one.

Thank you.

3
  • Use the debugger to point that out. And remind the Timestamp API "[...] it is recommended that code not view Timestamp values generically as an instance of java.util.Date." Commented Oct 30, 2012 at 14:36
  • 1
    d1.compareTo(ts); results 1, indicating there is a 1 nano difference or something of the likes. ___ I believe it's a bug, yes. Nice job finding it! Commented Oct 30, 2012 at 14:57
  • FYI, the terribly troublesome old date-time classes such as java.util.Date, java.util.Calendar, and java.text.SimpleDateFormat are now legacy, supplanted by the java.time classes built into Java 8 and later. See Tutorial by Oracle. Commented Sep 3, 2018 at 23:48

2 Answers 2

7

If you look at the internal representation and what is compared in the after() method, you see that for example for

millis = 1351607849957

you get a Date with

fastTime = 1351607849957

and a Timestamp with

fastTime = 1351607849000
nanos = 957000000

Since all that is compared is the fastTime part, you get your observed behaviour. As @user714965 points out above, you aren't supposed to treat a Timestamp as a Date.

Sign up to request clarification or add additional context in comments.

Comments

4

The API documentation of java.sql.Timestamp says:

Note: This type is a composite of a java.util.Date and a separate nanoseconds value. Only integral seconds are stored in the java.util.Date component. The fractional seconds - the nanos - are separate.

(That agrees with Keppil's answer).

It also says:

Due to the differences between the Timestamp class and the java.util.Date class mentioned above, it is recommended that code not view Timestamp values generically as an instance of java.util.Date. The inheritance relationship between Timestamp and java.util.Date really denotes implementation inheritance, and not type inheritance.

That means you should not treat Timestamp as a java.util.Date, which is what you are doing if you pass it to java.util.Date.after() (that method expects a java.util.Date - you're passing in a Timestamp, treating it as if it's a java.util.Date, which this comment says you shouldn't do).

This is ofcourse bad design in the standard Java library. If you need to work with dates and times, use Joda Time, a much better designed and more powerful library.

2 Comments

Yes, I'm aware of those differences (and incompatibilities, particularly in equals()) as well as Joda, but I'm looking for an explanation of this odd behaviour.
Note that you can dig into the source code of a class such as java.sql.Timestamp, you can find it in the file src.zip which is in your JDK installation directory.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.