Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use java.sql.Timestamp as real java.util.Date with JPA

I have a problem about the management of dates with milliseconds. I understand the need to use the TIMESTAMP to store milliseconds:

@Temporal(TIMESTAMP)
@Column(name="DATE_COLUMN", nullable = false)
@Override public java.util.Date getDate() { return this.date; }

But if I can't compare this date to another instance of java.util.Date, unless I pay attention to the order of equals() call, because this.date instance is a java.sql.Timestamp. How to get a java.util.Date from JPA ? Because the date that comes from JPA, even if the method signature is a java.util.Date is actually an instance of java.sql.Timestamp.

java.util.Date newDate = new Date(this.date.getTime());
this.date.equals(newDate) == false
newDate.equals(this.date) == true

I've try to modify my method in the persistence class:

@Override
public Date getDate() {
  return this.date == null ? null : new Date(this.date.getTime());
}

It's working, but it's not efficient with lots of data.

There are other options :

  • I could modify the design of my persistence class, using @PostLoad in order to create a java.util.Date from the persited date after I retrieve it.

  • I wonder if I can not get a result using a ClassTransformer?

Have you ever been confronted with this problem? What I do not correctly? What is the best way to handle this problem?

like image 933
chepseskaf Avatar asked Oct 25 '10 12:10

chepseskaf


People also ask

How is date stored in database 1 point Java sql date Java Util date Java sql datetime Java Util datetime?

Its main purpose is to represent SQL DATE, which keeps years, months and days. No time data is kept. In fact, the date is stored as milliseconds since the 1st of January 1970 00:00:00 GMT and the time part is normalized, i.e. set to zero. Basically, it's a wrapper around java.

How is date stored in database Java Util datetime Java Util datetime?

Correct Option: B. java. sql. Date is the datatype of Date stored in database.

What is the difference between Java sql date and Java Util date?

sql. Date just represent DATE without time information while java. util. Date represents both Date and Time information.


2 Answers

java.sql.Timestamp overrides the compareTo(Date) method, so it should be no problem using compareTo(..)

In short - java.util.Date and java.sql.Timestamp are mutually comparable.

Furthermore, you can always compare the date.getTime(), rather than the objects themselves.

And even further - you can use a long field to store the date. Or even a DateTime (from joda-time)

like image 35
Bozho Avatar answered Sep 18 '22 13:09

Bozho


TBH, I'm not sure of the exact status of this but there might indeed be a problem with the way Hibernate (which is your JPA provider, right?) handles TIMESTAMP columns.

To map a SQL TIMESTAMP to a java.util.Date, Hibernate uses the TimestampType which will actually assign a java.sql.Timestamp to your java.util.Date attribute. And while this is "legal", the problem is that Timestamp.equals(Object) is not symmetric (why on earth?!) and this breaks the semantics of Date.equals(Object).

As a consequence, you can't "blindly" use myDate.equals(someRealJavaUtilDate) if myDate is mapped to a SQL TIMESTAMP, which is of course not really acceptable.

But although this has been extensively discussed on the Hibernate forums, e.g. in this thread and this one (read all pages), it seems that Hibernate users and developers never agreed on the problem (see issues like HB-681) and I just don't understand why.

Maybe it's just me, maybe I just missing something simple for others, but the problem looks obvious to me and while I consider this stupid java.sql.Timestamp to be the culprit, I still think that Hibernate should shield users from this issue. I don't understand why Gavin didn't agree on this.

My suggestion would be to create a test case demonstrating the issue (should be pretty simple) and to report the problem (again) to see if you get more positive feedback from the current team.

Meanwhile, you could use a custom type to "fix" the problem yourself, using something like this (taken from the forum and pasted as is):

public class TimeMillisType extends org.hibernate.type.TimestampType {

    public Date get(ResultSet rs, String name) throws SQLException {
        Timestamp timestamp = rs.getTimestamp(name);
        if (timestamp == null) return null;
        return
            new Date(timestamp.getTime()+timestamp.getNanos()/1000000);
   }

}
like image 172
Pascal Thivent Avatar answered Sep 17 '22 13:09

Pascal Thivent