SQL Zone is brought to you in partnership with:

Senior Java developer, one of the top stackoverflow users, fluent with Java and Java technology stacks - Spring, JPA, JavaEE. Founder and creator of http://computoser.com and http://welshare.com . Worked on Ericsson projects, Bulgarian e-government projects and large scale recruitment platforms. Member of the jury of the International Olympiad in Linguistics and the Program committee of the North American Computational Linguistics Olympiad. Bozhidar is a DZone MVB and is not an employee of DZone and has posted 81 posts at DZone. You can read more from them at their website. View Full User Profile

How to Map Dates with Hibernate – Use joda-time

09.13.2011
| 20833 views |
  • submit to reddit

This is always a question – how to map temporal data in our hibernate entities – whether to use java.util.Date, java.util.Calendar or simply long. The correct answer is: neither of these. Use joda-time – the de-facto Java datetime API. Using it throughout the whole project is a no-brainer, but how to use it with hibernate – you can’t use @Temporal. Hibernate supports custom types, so there’s a little project that solves the issue – joda-time – hibernate support.

The user guide is pretty clear:

@Column
@Type(type="org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime fromDate;

However, there’s one issue with that library – it uses static final fields from hibernate, which requires recompilation if the version of hibernate changes (see here). For that reason you may need to extend the PersistentDateTime class, override the 2 methods that use the static final TIMESTAMP field, and copy the exact same code from the superclass.

Using joda-time throughout the whole project will save tons of headaches. So I strongly suggest the above mechanism to use joda-time in your hibernate entities as well.

 

From http://techblog.bozho.net/?p=499

Published at DZone with permission of Bozhidar Bozhanov, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Fabrizio Giudici replied on Wed, 2011/09/14 - 3:21am

There are some workarounds to prevent constant inlining, described by Bloch and others - for instance, prepending a dummy expression between the value such as:

public static final Object CONSTANT = (1 != 0) ? SomeOther.VALUE : null;

I wonder why  JodaTime contrib doesn't use the trick.  When you explain to some customer that you have to "patch" JodaTime Hibernate contrib, they usually prefer not to use it (keeping java.util.Date only for persistence, and JodaTime for the rest of the application).

Artur Biesiadowski replied on Wed, 2011/09/14 - 4:45am

I'm suprised that Hibernate is changing their public API in incompatible ways (and public static integer constants values ARE public api because of inlining).

Does it happen often?

Jose Smith replied on Wed, 2011/09/14 - 8:02am

Honestly this is one of the reasons why I dropped Hibernate in my project. An ORM has one primary job - map objects to databases. On page one (or two) of the hibernate docs it should show you how you can easily change how an object is mapped.

In my case I had a simple JODA LocalDate in my domain object (a date without time or timezone). I wanted to map this to a MySQL DATE type (a simple Year Month Day type - no timezones). It should be fairly straightforward, but as a beginning hibernate user I kept getting frustrated trying several different methods - none of which were working.

Finally, I found the joda-hibernate library, and sure it persisted my object, but when I looked at the source code it pushed me over the edge:

StandardBasicTypes.DATE.nullSafeSet(preparedStatement, ((LocalDate) value).toDateTimeAtStartOfDay().toDate(), index);

What??? I spent all this effort to make sure I don't run into any issues with timezones and now my LocalDate is being persisted as a Date with time???? As it is you have to be aware of the timezone conversions at the database column level, jdbc driver level, and now I have this black box in my application code also mangling my simple date.

After looking at the joda-hibernate source I had enough knowledge to write my own mapper, but that was the final nail in the coffin - I switched to spring's jdbctemplate and 5 minutes later I had my JODA LocalDate persisted as a MySQL DATE with one basic line of code.

John J. Franey replied on Wed, 2011/09/14 - 11:23am in response to: Jose Smith

@Jose, where is the sense in persisting a date without a timezone? Timezone is needed even with Date sql type. I am in New York 12:30 PM on Wednesday, 9/14. It is 00:30 AM on Thursday, 9/15 in Hong Kong. An event that happens right now, happens on 9/14 for me, and 9/15 for my users in Hong Kong. If I store the date (without a timezone) for an event that happened today, my users in Hong Kong would read it as if it happened on 9/14, which is wrong; it really happened on 9/15 for them. Your complaint against hibernate is it would not let you do something senseless. Cheers.

Fabrizio Giudici replied on Wed, 2011/09/14 - 11:37am in response to: John J. Franey

John, the basic point is that JodaTime provides a LocalDate, which is a Date without timezone. This should be enough to proof that sometimes people need that. In SQL there is the DATE type, without timezone: clearly, even database users think that sometimes people need that. Now, an ORM must map Java to SQL. Both worlds have the concept of a date without timezone, thus Jose's complaints are meaningful.

Jose Smith replied on Wed, 2011/09/14 - 12:19pm in response to: John J. Franey

Besides the reasons Fabrizio stated, there's a few other reasons.

Timezone handling is JDBC driver dependent. For example, MySQL translates dates to the database's timezone while Postgres translates the date based on the JVM timezone and SQLite performs no conversion. To make matters worse, the various databases have different date types, with and without timezone, which are often misleading.

If you don't want to get burned by all these conversions in various layers, you can store a DATETIME (MySQL - a date and time without timezone) and timezone in two separate columns.

Andy Jefferson replied on Wed, 2011/09/14 - 12:20pm

Surprising that Hibernate doesn't handle such things seamlessly ... timezones, recompiling etc!; with DataNucleus you can persist JodaTime or javax.time (JSR0310) types with little hassle.

John J. Franey replied on Wed, 2011/09/14 - 3:41pm

@Fabrizio - I'm not questioning the need for LocalDate, although I don't see myself using it - I don't accept its mere existence as proof that it is needed or useful. From my viewpoint, as long as LocalDate stays in-core, there is not an issue. Once it is persisted, either to a database or a string, to be later parsed and reloaded into memory, there is an issue. To share dates this way is imprecise, and an application that goes without timezones in persisted dates would be less robust than those that use them. However, I'd concede that an application that runs in only one timezone is not as exposed, and timezone may not even be a factor to other types of applications. Sure.

What is a date without a timezone? How is it useful? I can't see it. If you scheduled an important event, the timezone is as important as the day and time, although, it is often implied. However, an implied timezone is not the same as a missing timezone. The timezone is a reference. Without it, a date is just a string.

Jose Smith replied on Wed, 2011/09/14 - 4:20pm in response to: John J. Franey

Here's a simple example:

Birthday

Are you going to persist a birthday based on the timezone in which the person is born? How do you render this birthday to other users in other time zones? Surely you don't want to use their timezone preference - or they might see the person being born a day early or a day late. This is a classic example of a date which should not have timezone associated with it and including any sort of "time" is just going to be prone to bugs.

There aren't many cases like this, but my other points you didn't address are still valid. There're lots of issues regarding persisting dates using Java's Date class. I don't claim to be an expert in this area, but I know enough that I'm weary to add further abstractions.

If I have a java.util.Date that presents some instance in time, I want to persist exactly that instance without any conversions (internally it already has ms since epoch so there's no need to do any conversion). But if you look into the source code of MySQL's PreparedStatement class for instance, you'll see it doesn't simply persist myDate.getTime(). It's doing some whacky conversion into the database's timezone. I suppose this is why the general rule is to set all server and database timezones to UTC - but in my opinion this seems like a bandaid.

So one clear option is to persist a long yourself representing time since epoch. Another is to persist a datetime without timezone and the timezone in two columns. In the latter you need the ability to persist a "date and time without timezone". Maybe some java timezone gurus can chime in.

Fabrizio Giudici replied on Thu, 2011/09/15 - 5:44am

Birthday is just an example, the broader generalization is that sometimes a date (or datetime) is meaningful in its own timezone. For instance, if I have an application that performs periodic tasks during the day (such as turning on and off the light, or some equipment), it does make sense to refer to the local time rather than UTC (even inside the same timezone, if it used UTC you would be forced to perform adjustments when daylight savings are enabled / disabled, which is an over complexity: the point is that I'm supposing that the specifications say "always the same hour in local time", and this concept must be represented as is in my model and persistence storage).

Other examples might be a repository of historical events or holidays - I'm thinking of e.g. a repository of knowledge (e.g. popular dates in the world). For instance, May 1st is celebrated in many countries as a festivity and every country refers generically to it as May 1st, not counting the timezone; people in New Zeland know that the US Independence Day is July 4th, even though in their timezone it's probably July 5th, etc.

Lieven Doclo replied on Thu, 2011/09/15 - 8:27am

Take a look at how the Hibernate 4.x usertype mappings work for Joda Time. Jose's remark may have been correct in the past, as of Hibernate 4.x, this is no longer an issue. Frameworks evolve and change for the better over time (most of the time). Joda Time's Hibernate integration is no exception. But one small remark: last time I checked, the Hibernate integration is open source. Instead of cursing the code, submit a patch. I bet in this case, it wouldn't have cost you more than the five minutes you spend on writing the low-level spring-jdbc code.

Bozhidar Bozhanov replied on Thu, 2011/09/15 - 8:45am

By the way, it is rarely a good idea to store dates with timezones. Store them in a fixed (UTC) timezone, and then convert it to a specific timezone when displaying to users.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.