Different temporal types in JPA

Temporal information is very precious for all marketing purposes, as birthday e-mailing or several other reminders. JPA has specific annotation to handle this type - @Temporal.

Through this article we'll explore 3 temporal types supported by JPA specification: DATE, TIME and TIMESTAMP. In the first part, we'll explain them before writing some examples in the second part.

@Temporal in JPA

@Temporal is an annotation destined to be used to represent datetime fields in JPA entities. Depending on database field type, @Temporal can be created as one of three available entries in javax.persistence.TemporalType enumeration :

Example of TemporalType.DATE

We'll begin our tests by DATE fields, mapped as below in JPA entity (only DATE-related fields and methods are shown):

@Entity
@Table(name = "shopping_cart")
public class ShoppingCart {
  private Date creationDate;

  @Temporal(DATE)
  @Column(name="create_date")
  public Date getCreationDate() {
    return this.creationDate;
  }

  public void setCreationDate(Date creationDate) {
    this.creationDate = creationDate;
  }
}

And the test illustrating TemporalType.DATE specificities:

/**
 * Test cases for {@link javax.persistence.TemporalType} annotation.
 *
 * Expected tables before the tests :
 * <pre>
 * mysql> select * from `order`;
 * +----+------------------+---------+-----------+---------------------+
 * | id | shopping_cart_id | user_id | state     | updated_date        |
 * +----+------------------+---------+-----------+---------------------+
 * |  1 |                1 |       1 | CREATED   | 2014-10-28 19:00:00 |
 * |  2 |                2 |       3 | CONFIRMED | 2014-10-28 19:15:00 |
 * +----+------------------+---------+-----------+---------------------+
 * 2 rows in set (0.00 sec)
 *
 * mysql> select id, create_date, last_used_date, last_update_date from shopping_cart;
 * +----+---------------------+---------------------+---------------------+
 * | id | create_date         | last_used_date      | last_update_date    |
 * +----+---------------------+---------------------+---------------------+
 * |  1 | 2014-10-28 10:43:31 | 2014-11-11 11:11:11 | 2014-10-28 10:43:31 |
 * |  2 | 2014-10-28 10:43:31 | 2014-11-11 11:11:11 | 2014-10-28 10:43:31 |
 * +----+---------------------+---------------------+---------------------+
 * 2 rows in set (0.00 sec)
 * </pre>
 *
 * @author Bartosz Konieczny
 */
public class TemporalTypeTest extends AbstractJpaTester {

  @Test
  public void testDateTemporal() {
    Query query = entityManager.createQuery("SELECT sc FROM ShoppingCart sc WHERE id = :id");
    query.setParameter("id", 1l);
    ShoppingCart shoppingCart = (ShoppingCart) query.getSingleResult();
    assertEquals("Creation date was bad formatted", "2014-10-28",
            shoppingCart.getCreationDate().toString());
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("CET"));
    cal.setTime(shoppingCart.getCreationDate());
    assertTrue("TemporalType.DATE shouldn't contain time information", cal.getTime().toString().contains("00:00:00 CET"));
  }

}

Example of TemporalType.DATETIME

TemporalType.DATETIME is also represented by ShoppingCart fields:


private Date lastUpdateDate;
private Date lastUseDate;

// represented as DATETIME column in database
@Temporal(TIMESTAMP)
@Column(name="last_update_date")
public Date getLastUpdateDate() {
  return this.lastUpdateDate;
}

// represented as TIMESTAMP column in database
@Temporal(TIMESTAMP)
@Column(name="last_used_date")
public Date getLastUseDate() {
  return this.lastUseDate;
}

public void setLastUpdateDate(Date lastUpdateDate) {
  this.lastUpdateDate = lastUpdateDate;
}

public void setLastUseDate(Date lastUseDate) {
  this.lastUseDate = lastUseDate;
}

And some veryfications to illustrate DATETIME features are defined as:

@Test
public void testDateTimeTemporal() {
  Query query = entityManager.createQuery("SELECT sc FROM ShoppingCart sc WHERE id = :id");
  query.setParameter("id", 1l);
  ShoppingCart shoppingCart = (ShoppingCart) query.getSingleResult();
  // result should be formatted in the same way for both, TIMESTAMP and DATETIME types
  assertEquals("Last updated date was bad formatted", "2014-10-28 10:43:31.0",
    shoppingCart.getLastUpdateDate().toString());
  assertEquals("Last used date was bad formatted", "2014-11-11 11:11:11.0",
    shoppingCart.getLastUseDate().toString());

}

Example of TemporalType.TIME

The last examined type is TemporalType.TIME. It's used in OrderCrated entity to represent the time of order creation:

@Entity
@Table(name = "`order`")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "state")
public abstract class Order {
  protected Date lastUpdated;

  @Temporal(TemporalType.TIME)
  @Column(name = "updated_date")
  public Date getLastUpdated() {
    return this.lastUpdated;
  }

  public void setLastUpdated(Date lastUpdated) {
    this.lastUpdated = lastUpdated;
  }
  
}

@Entity
@DiscriminatorValue("CREATED")
public class OrderCreated extends Order {
}

Tests for this case look like:

@Test
public void testTimeTemporal() {
  Query query = entityManager.createQuery("SELECT oc FROM OrderCreated oc WHERE id = :id");
  query.setParameter("id", 1l);
  OrderCreated order = (OrderCreated) query.getSingleResult();
  assertEquals("Order last update time was bad formatted", "19:00:00",
    order.getLastUpdated().toString());
  Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("CET"));
  cal.setTime(order.getLastUpdated());
  assertEquals("TemporalType.TIME should be set by default to 'zero epoch'", 
    "Thu Jan 01 19:00:00 CET 1970", cal.getTime().toString());
}

This time we described a little bit the world of datetime dimension in JPA-database relation. We saw that all of 3 available TemporalType fields reflect well data stored in database layer - when table stores only a time, mapped Java object will represent only a time. The same dependency is applied for date type. For more complete case, we can use DATETIME type which holds as well date as the time.


If you liked it, you should read:

📚 Newsletter Get new posts, recommended reading and other exclusive information every week. SPAM free - no 3rd party ads, only the information about waitingforcode!