Today, I feel the urge to document this. Yes, even though there had been ways which databases and Java JDBC driver/Persistent engines deal with Date, Time, DateTime, Calendar, Timestamp and whatever database data type or Java class types that represent dates and time and even time zone had long been there since the very beginning, but still many developers are often confused with how to persist fields that represents date, time, date-time or timestamp through EJB3/JPA. So, this article is mainly about 3 very simple ways that we could achieve this.
I have to first admit that I am no expert in the scientific facts of representation of dates and time in the java.util.Date or java.util.Calendar class. But I do believe that by simply being able to understand a few characteristics of all these date and time related data types, whether if it is database specific or in terms of Java class types, it could definitely help you to develop applications/systems that are correct and accurate.
In this article, I want to show you three ways to code your EJB3/JPA Entity class when it comes to properties that deal with date, time, date-time and timestamp, by using a database table structure below in MySQL DB:
This “DATEANDTIMESTUFF” table is a simple table that captures fields of different DATE, TIME, DATETIME and TIMESTAMP data in the MySQL database. We’ll be using this table as a reference to the below Java JPA persistent class fields.
Method 1: Data Type Representation Using java.sql.Date, java.sql.Time and java.sql.Timestamp
@Column(name = "DATE_FIELD") private java.sql.Date dateField; @Column(name = "TIME_FIELD") private java.sql.Time timeField; @Column(name = "DATETIME_FIELD") private java.sql.Timestamp dateTimeField; @Column(name = "TIMESTAMP_FIELD") private java.sql.Timestamp timestampField;
You can always represent date, time and timestamp field with the specific java.sql.Date, java.sql.Time and java.sql.Timestamp data type class. Do take note that these classes will store only the value of the date, time and datetime together, without any information on the geographical location, region, Greenwich Mean Time Offset (e.g. GMT-8:00, etc.) or any other extended date and time details.
When Should You Use Method 1?
If your application only requires to store date and time values, without the need to store extended detail of dates and time like server GMT offset or storing different date and time in different region or time zone, this method is sufficient for most.
Method 2: Date, Time and Timestamp Representation Using java.util.Date
@Temporal(TemporalType.DATE) @Column(name = "DATE_FIELD") private java.util.Date dateField; @Temporal(TemporalType.TIME) @Column(name = "TIME_FIELD") private java.util.Date timeField; @Temporal(TemporalType.TIMESTAMP) @Column(name = "DATETIME_FIELD") private java.util.Date dateTimeField; @Temporal(TemporalType.TIMESTAMP) @Column(name = "TIMESTAMP_FIELD") private java.util.Date timestampField;
Since the java.util.Date class could store both date and time information, we need to have an extra @Temporal annotation with the correct TemporalType attribute (TemporalType.DATE, TemporalType.TIME or TemporalType.TIMESTAMP). In the Java EE API documentation, it was written that the @Temporal annotation will map the java.util.Date or java.util.Calendar data type as java.sql.Date, java.sql.Time or java.sql.Timestamp. But here when using MySQL as the database, I happen to discover that persisting the field as java.sql.Time is rather different as compare to persisting the field as java.util.Date with @Temporal(TemporalType.TIME). The result goes like this:
If you persist as java.sql.Time into the DB, retrieve it, convert the data back to java.util.Date and print out the values by toString() method, the date is always kept at 1970 Jan 1.
However, if you persist the property field as java.util.Date with @Temporal(TemporalType.TIME) into the DB and do the same thing by retrieving it and print out the values by toString() method, the date will be the date when the data was persisted.
So, do watch out of this very minor difference/behavior, which might cause inconsistency in result expectation depending on your application.
When Should You Use Method 2?
Referring to the above stated behavior, use Method 2 when you need to store the server/application’s date and GMT values with the date, time or timestamp field, if that it is necessary.
Method 3: Date, Time and Timestamp Representation Using java.util.Calendar
@Column(name = "DATE_FIELD") @Temporal(TemporalType.DATE) private java.util.Calendar dateField; @Column(name = "TIME_FIELD") @Temporal(TemporalType.TIME) private java.util.Calendar timeField; @Column(name = "DATETIME_FIELD") @Temporal(TemporalType.TIMESTAMP) private java.util.Calendar datetimeField; @Column(name = "TIMESTAMP_FIELD") @Temporal(TemporalType.TIMESTAMP) private java.util.Calendar timestampField;
The same as java.util.Date data type, if a field is represented as java.util.Calendar, it will require the @Temporal annotation with the TemporalType attribute specified.
When Should You Use Method 3?
Method 3 is very suitable especially if you need to store date, time or datetime data with reference to different region, timezone or geographical details. The java.util.Calendar class is one of the most flexible and highly powerful class to capture dates and time with lots of manipulations.
Therefore, if you are developing application which requires international date and time information capturing, java.util.Calendar class as the property field data type is the preferred choice.
I highly suggest that you experiment the values with different data types against different databases to see the behavior of the persisted data, by persisting, retrieving and converting the data. Do also perform a “SELECT…ORDER BY…” SQL statement to see if the results are according to your requirements and expectation.
Hope this helps.