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. The Timestamp.equals(Object) method never returns true when passed an object that isn't an instance of java.sql.Timestamp, because the nanos component of a date is unknown.
I think that explains it. I would expect that Date.before() compares the Date component of the Timestamp, so the extra millisecond is ignored.
As far as I understand, the method a.before(b) simply compares the difference between a.getTime() and b.getTime(). The method equals is never called on Timestamp.
When constructing a Timestamp using a milliseconds argument, there are no nanoseconds.
So strictly following Javadoc for new Timestamp(long time) and new Date(long time), which I used in the example, I would expect before(...) to return true in this case.
Kjeld Sigtermans wrote:When constructing a Timestamp using a milliseconds argument, there are no nanoseconds.
Yes there are. The milliseconds from the Date object are stored in the nanoseconds part of the Timestamp. The Date part of the Timestamp only contains complete seconds. So when comparing a Date with a Timestamp (whether for the equals method or the before method) only the complete seconds will be considered.
If you look at the source code for Timestamp, the first thing the single parameter constructor does is
i.e. it sets the milliseconds component to zero. So the only time your code would work as you expect is if the milliseconds component of now was 999, so adding 1 would click over to a new second.
As far as I know, the precision of Date is milliseconds, not seconds. When using new Date(), a Date is constructed based on the System millis, calling the overloaded new Date(long millis). When using getTime() that value is returned (however not always, the source does some checks I did not go in to).
The constructor of Timestamp(long millis) divides the given millis into a millis part and a nanos part. So the millis part always ends with 000 and the nanos part holds that lower significance multiplied by a million.
The precision of Timestamp is in nanoseconds, when calling its getTime() method, the number of nanosecs are divided by a million again and added to the millisecs part.
Therefore, when comparing Date.getTime and Timestamp.getTime both are millisecond representations, having a millisecond precision.
Regarding the other comment: I use JodaTime extensively, but I still want to know why my code example returns false.
Edit: it's even worse, sometimes it returns true...
Kjeld Sigtermans wrote:The constructor of Timestamp(long millis) divides the given millis into a millis part and a nanos part. So the millis part always ends with 000 and the nanos part holds that lower significance multiplied by a million.
No. The constructor divides it into a seconds part and a nanos part. Yes, the Date part could cope with millisecond accuracy. But that's not how it's been implemented.
But, when calling before or after, and indirectly its getTime() method, the nanos are divided by a million and added to the millis (seconds) part again. So the given constructor parameter is restored for comparison.
Meanwhile I noticed my code example sometimes returns true.
You create a Date object - lets say 09-03-2011 12:28:34.287
You then pass the number of milliseconds this represents (+1) (lets say that's XXX288 - only the miiliseconds part is important) to the Timestamp constructor
The constructor rounds that time down to the nearest second so it is now XXX000 and passes this to its super constructor. So the Date part of the Timestamp now represents the time 09-03-2011 12:28:34.000.
You now call which returns false, which is correct because 09-03-2011 12:28:34.287 is after 09-03-2011 12:28:34.000.
The one time your code will return true is if the milliseconds part of now is 999. Adding one will increment the number of seconds, so now you will be comparing 09-03-2011 12:28:34.999 to 09-03-2011 12:28:35.000.
Look at the source code for Timestamp and it should be clearer what is happening.
It will only return fastTime (and therefore the rounded down value) when some variable cdate is null. They should have used getTime() to make the comparison. Then Timestamp.getTime() would have returned the correct millisecond value.
Meanwhile I went with Jesper's tip to use JodaTime and added this:
It does correctly return false.