Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map postgresql "timestamp with time zone" in a JPA 2 entity

I have a JPA 2 application ( with Hibernate 3.6 as the JPA implementation ) that uses Postgresql ( with the 9.0-801.jdbc3 JDBC driver ).

I am having trouble mapping "timestamp with time zone" fields into my JPA entities.

Here is an example:

CREATE TABLE theme (   id serial NOT NULL,   # Fields that are not material to the question have been edited out   run_from timestamp with time zone NOT NULL,   run_to timestamp with time zone NOT NULL,   CONSTRAINT theme_pkey PRIMARY KEY (id ),   CONSTRAINT theme_name_key UNIQUE (name ) ) 

I have tried to map as follows:

@Entity @Table(schema = "content", name = "theme") public class Theme extends AbstractBaseEntity {     private static final long serialVersionUID = 1L;      @Column(name = "run_from")     @NotNull     @Temporal(TemporalType.TIMESTAMP)     private Date runFrom;      @Column(name = "run_to")     @NotNull     @Temporal(TemporalType.TIMESTAMP)     private Date runTo;      /* The rest of the entity has been edited out */ 

I keep on getting an exception with the following root cause: Caused by: org.hibernate.HibernateException: Wrong column type in public.backend_themetopic for column created. Found: timestamptz, expected: date

What I have tried

  • replacing java.util.Calendar with java.util.Date - made no difference
  • using java.sql.Timestamp - complained that I cannot apply the @Temporal annotation to a Timestamp
  • using org.joda.time.DateTime with a custom @Type annotation ( @Type(type="org.joda.time.contrib.hibernate.PersistentDateTimeTZ") ) also did not work

Constraints

  • This application interacts with a "legacy system" - so, changing the types of the date fields is not a good option

My question is: how should I map these timezone aware timestamps into my JPA entities?

like image 972
Ngure Nyaga Avatar asked Nov 13 '12 08:11

Ngure Nyaga


People also ask

How does Postgres store timestamp with timezone?

The timestamptz datatype is a time zone-aware date and time data type. PostgreSQL stores the timestamptz in UTC value. When you insert a value into a timestamptz column, PostgreSQL converts the timestamptz value into a UTC value and stores the UTC value in the table.

Is timestamp stored with timezone?

@Colin'tHart timestamp and timestamptz are both stored the same way. There is no time zone information being stored in a timestamptz , but instead it is converted to UTC for storage. I'd say, always use timestamptz when the timestamps in question denote absolute time. That's all what timestamptz means.

How is timestamp stored in PostgreSQL?

By casting "TimeStamp" to date you throw away the time part of the timestamp, so all values within one day will be considered equal and are returned in random order. It is by accident that the first rows appear in the order you desire. Don't cast to date in the ORDER BY clause if the time part is relevant for sorting.

How does timestamp with timezone work?

For timestamp with time zone , the internally stored value is always in UTC (Universal Coordinated Time, traditionally known as Greenwich Mean Time, GMT ). An input value that has an explicit time zone specified is converted to UTC using the appropriate offset for that time zone.


2 Answers

I eventually made this "work" - in a hackish sort of way - by turning off schema validation.

Previously, I had <property name="hibernate.hbm2ddl.auto" value="validate"/>"hibernate.hbm2ddl.auto" in my persistence.xml. When I commented out this property, my app server started and the model "worked".

The final form of my entity was:

@Entity @Table(schema = "content", name = "theme") public class Theme extends AbstractBaseEntity {     private static final long serialVersionUID = 1L;      @Column(name = "run_from", columnDefinition = "timestamp with time zone not null")     @NotNull     @Temporal(TemporalType.TIMESTAMP)     private Date runFrom;      @Column(name = "run_to", columnDefinition = "timestampt with time zone not null")     @NotNull     @Temporal(TemporalType.TIMESTAMP)     private Date runTo;      /* Getters, setters, .hashCode(), .equals() etc omitted */ 

After reading quite a bit on this, I got the impression is that there is no easy way to map Postgresql timestamp with time zone columns.

Some JPA implementation + database combinations support this natively ( EclipseLink + Oracle is one example ). For hibernate, with jodatime extensions, it is possible to store timezone aware timestamps using a normal timestamp + a varchar field for the timezone( I could not do that since I was constrained from changing the database schema ). Jadira user types or completely custom user types can also be used to tackle this problem.

I need to note that my use-case for this entity is "read only", so I could get away with a seemingly naive "solution".

like image 173
Ngure Nyaga Avatar answered Oct 08 '22 08:10

Ngure Nyaga


Add @Column(columnDefinition= "TIMESTAMP WITH TIME ZONE")

@Column(name = "run_from", columnDefinition= "TIMESTAMP WITH TIME ZONE") @NotNull @Temporal(TemporalType.TIMESTAMP) private Date runFrom; 
like image 37
Alexei Osipov Avatar answered Oct 08 '22 08:10

Alexei Osipov