user829237
user829237

Reputation: 1759

Hibernate Criteria extracting Year from date

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?

Upvotes: 13

Views: 22810

Answers (3)

Tim Van Laer
Tim Van Laer

Reputation: 2534

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)

Upvotes: 6

Vipul
Vipul

Reputation: 836

Use Restrictions.sqlRestriction that will solve your problem

Upvotes: 5

Pau Kiat Wee
Pau Kiat Wee

Reputation: 9505

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));

Upvotes: 14

Related Questions