The java.util.Date class is the "normal" timestamp class in the Java standard library. It's basically a wrapped up POSIX timestamp, except that 64-bit signed value is an expression of the number of milliseconds since the epoch instead of the usual seconds. A strange choice to begin with, but not really unreasonable.
Databases may represent timestamps to a higher resolution than milliseconds, in the general case. When interacting with a database with JDBC, one doesn't want to lose precision on timestamp values merely because of Date's chosen resolution. JDBC chose to address this by introducing the Timestamp class, which records times to nanosecond resolution. Presumably since most of the behaviour and and interface on Date also make sense for Timestamp, Timestamp derives from Date. But hold on, take a look at that note on Timestamp:
Note: This type is a composite of a
java.util.Dateand a separate nanoseconds value. Only integral seconds are stored in the
java.util.Datecomponent. The fractional seconds - the nanos - are separate. The
Timestamp.equals(Object)method never returns
truewhen passed an object that isn't an instance of
java.sql.Timestamp, because the nanos component of a date is unknown. As a result, the
Timestamp.equals(Object)method is not symmetric with respect to the
java.util.Date.equals(Object)method. Also, the
hashcodemethod uses the underlying
java.util.Dateimplementation and therefore does not include nanos in its computation.
Due to the differences between the
Timestampclass and the
java.util.Dateclass mentioned above, it is recommended that code not view
Timestampvalues generically as an instance of
java.util.Date. The inheritance relationship between
java.util.Datereally denotes implementation inheritance, and not type inheritance.
Woah! So, Timestamp is-not-a Date! This note is essentially a warning to not treat a Timestamp polymorphically as if it were a Date. Now this isn't in itself always necessarily evil. Although, in C++, you might think about using private or protected inheritance with some using declarations, or aggregation. In Java, you're stuck with the choice of aggregation and re-offering a semantically-different-but-syntactically-the-same interface on Timestamp. If a Timestamp is not usable as a Date, then aggregation seems like the right choice here.
But wait a minute. Is there really a need for Timestamp to be unusable as a Date? Why did they chose to stop storing the milliseconds of the timestamp value in the Date part of the object? That decision doesn't really make any sense. Why wouldn't you just leave the Date part of the class as-is and allow it to store whole milliseconds, and then have an additional field that stores the fractional milliseconds (down to the resolution of nanoseconds)?
This wouldn't require any changes in the Timestamp interface at all. The class could still offer getTime() and getNanos() methods and so on cheaply, and, critically, it would then be true that a Timestamp is-a Date! You could compare two Timestamp values through their Date.equals() interface (since the Timestamp version would be called). You could even compare Date values to Timestamp values with reasonably semantics: if you use the Date.equals(Timestamp) interface, you just ignore the fractional part, which is presumably what you meant, since you used an interface that has nothing to do with fractional parts; if you use the Timestamp.equals(Date) interface, it can only be true if the Timestamp has zero fractional milliseconds.
Alas, this is not the case, which makes the Timestamp class far less useful
public class Foo
public static void main(final String args)
System.out.println("D == T: "
+ (new Date(1000)).equals(new Timestamp(1000)));
System.out.println("T == D: "
+ (new Timestamp(1000)).equals(new Date(1000)));
$ java Foo
D == T: true
T == D: false
And, in case you're not yet convinced that this is complete madness, check out the compareTo(Date) method, which states:
Timestampobject to the given
Date, which must be a
Timestampobject. If the argument is not a
Timestampobject, this method throws a
Timestampobjects are comparable only to other
So if you pass a Date to the compareTo(Date) method, it throws. Madness.