Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate Criteria extracting Year from date

Tags:

java

hibernate

Im creating a hibernate criteria that will check if a contract is/has been valid during a year. The contract has a start and end-date as a standard date-field.

So being used to SQL-SERVER, i would think something in the lines of this SQL:

SELECT * FROM CONTRACT WHERE YEAR(startDate) <= ? AND YEAR(endDate) >= ?

The questionmark is the given year as an integer.

So how to transform this to a hibernate criteria?

int year = 2011; //Just a testyear for example purposes.
DetachedCriteria criteria = DetachedCriteria.forClass(Contract.class)
    .add(Restrictions.le("startDate", year))
    .add(Restrictions.ge("endDate", year));

As you can see, i am missing the bit where i convert the date's to a year so it can be compared. Naturally my code does not run as it is.

Any suggestion on how to get the desired results?

like image 673
user829237 Avatar asked May 06 '12 12:05

user829237


2 Answers

It seem like the API does not directly support what you wanted, but there is workaround that you might consider.

Solution 1:

DetachedCriteria criteria = DetachedCriteria.forClass(Contract.class)
    .add(Restrictions.le("startDate", toEndOfYear(year))
    .add(Restrictions.ge("endDate", toStartOfYear(year)));

public Date toStartOfYear(int year) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.YEAR, year);
    calendar.set(Calendar.DAY_OF_YEAR, 0);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    return calendar.getTime();
}

public Date toEndOfYear(int year) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.YEAR, year);
    calendar.set(Calendar.DAY_OF_YEAR, 0);
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND,-1);
    return calendar.getTime();
}

Example output of the two methods:

System.out.println(toStartOfYear(2013));
System.out.println(toEndOfYear(2013));

Mon Dec 31 00:00:00 MYT 2012
Sun Dec 30 23:59:59 MYT 2012

Solution 2:

DetachedCriteria criteria = DetachedCriteria.forClass(Contract.class)
    .add(Restrictions.sqlRestriction("YEAR(startDate) >= ? ", year,Hibernate.INTEGER))
    .add(Restrictions.sqlRestriction("YEAR(endDate) <= ? ", year,Hibernate.INTEGER));
like image 117
Pau Kiat Wee Avatar answered Sep 18 '22 15:09

Pau Kiat Wee


If you use JPA criteriaBuilder, you can use the criteriaBuilder.function method. E.g.

contractRepository.findAll(new Specification<Contract>() {
   @Override
   public Predicate toPredicate(Root<Contract> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
     return cb.ge(cb.function("year", Integer.class, root.get(Contract_.endDate)), year);
   }
});

(I use Spring Data Specifications in this example to query the database. contractRepository is thus of type JpaSpecificationExecutor)

like image 23
Tim Van Laer Avatar answered Sep 19 '22 15:09

Tim Van Laer