【问题标题】:Count number of days between 2 dates in JPA计算JPA中2个日期之间的天数
【发布时间】:2014-09-19 10:11:11
【问题描述】:

我需要计算 JPA 中两个日期之间的天数。

例如:

CriteriaBuilder.construct(
  MyCustomBean.class
  myBean.get(MyBean_.beginDate), //Expression<Date>
  myBean.get(MyBean_.endDate), //Expression<Date>
  myDiffExpr(myBean) //How to write this expression from the 2 Expression<Date>?
);

到目前为止,我试过了:

  1. CriteriaBuilder.diff()。但它无法编译,因为此方法需要一些 N extends Number 并且 Date 没有扩展 Number

  2. 我尝试扩展PostgreSQL82Dialect(因为我的目标数据库是 PostgreSQL):

    public class MyDialect extends PostgreSQL82Dialect {
    
      public MyDialect() {
        super();
        registerFunction("datediff", 
        //In PostgreSQL, date2 - date1 returns the number of days between them.
        new SQLFunctionTemplate(StandardBasicTypes.LONG, " (?2 - ?1) "));
      }
    }
    

这样编译,请求成功,但返回的结果不一致(今天和明天之间的78天)。

你会怎么做?

【问题讨论】:

  • 如何尝试使用 #1 date.getTime(),因为它是 Long,另一种方法是尝试在 JPA 中使用本机 sql 查询?
  • @ANyarThar 你有办法从Expression&lt;Date&gt; 得到这个Expression&lt;Long&gt;(日期时间)吗?
  • 我的建议就像下面的答案。
  • 请编写您要使用的示例查询/语句。我仍然不确定你想要实现什么。

标签: java postgresql jpa


【解决方案1】:

1) CriteriaBuilder.diff()。但它无法编译,因为此方法需要一些 N 扩展 Number 并且 Date 不扩展 Number。

如下所示,尝试为每个日期使用 no of mili seconds。

Date date = new Date()//use your required date
long millisecond = date.getTime();//Returns no of mili seconds from 1 Jan, 1970 GMT

Java 中的 Long in Number 并且根据自动装箱,您可以使用它。这可能会有所帮助。

【讨论】:

  • 我的日期是Expression&lt;Date&gt;。如何提取它的日期时间? (例如,构建一个可以与CriteriaBuilder.diff 一起使用的Expression&lt;Long&gt;?我编辑了问题以使其更清晰。
【解决方案2】:

您似乎正在寻找一个使用 JPQL 的解决方案来执行像 SELECT p FROM Period p WHERE datediff(p.to, p.from) &gt; 10 这样的查询。

恐怕 JPQL 中没有这样的功能,所以我建议使用原生 SQL。如果使用 Hibernate 的 SQLFunctionTemplate 扩展方言,您的想法非常聪明。我宁愿将其更改为使用DATE_PART('day', end - start),因为这是使用 PostgreSQL 实现日期之间的天数差异的方法。

你也可以定义你的函数in PostgreSQL and using it with criteria function()

'CREATE OR REPLACE FUNCTION "datediff"(TIMESTAMP,TIMESTAMP) RETURNS integer AS \'DATE_PART('day', $1 - $2);\' LANGUAGE sql;'

cb.function("datediff", Integer.class, end, start);

【讨论】:

  • 我试过了,但 end - start 被 Postgres 视为 Integer,相应的功能不起作用。我的问题可能不是来自模板,而是来自我使用它的方式。我还在调查。
  • end - start 在 PostgreSQL 中应该产生 INTERVAL 类型。我认为没有对应的Java类型。
  • JPA 甚至不能减去日期这一事实充分说明了它在现实世界中的用处。
  • 我不会走那么远。 JPQL 是 JPA 的一种查询语言,无法做到这一点。但是JPA?当然可以。只需选择两个日期,您就可以将其作为 Java 对象,并且您可以通过多种不同的方式将其相减。
  • @zbigniewTomczak 终于发现问题出在(?2 - ?1)部分。我提出了一个新问题:stackoverflow.com/questions/25037380/…
【解决方案3】:

JPA 2.1 规定在 JPQL 语句中使用“FUNCTION(funcName, args)”。这允许这样的处理。

【讨论】:

  • 什么是 Oracle 函数来调用日期减法?
【解决方案4】:

我终于发现问题出在参数的顺序不是我期望的那样:

/*
 *(?2 - ?1) is actually equivalent to (? - ?).
 * Hence, when I expect it to evaluate (date2 - date1), 
 * it will actually be evaluated to (date1 - date2)
 */
new SQLFunctionTemplate(StandardBasicTypes.LONG, " (?2 - ?1) "));

我打开了new question 以了解此行为是错误还是功能:

【讨论】:

  • Hibernate 中的实现对我来说看起来不错。我没有从版本 3.3.0 更改。您是否在日志中确认了这一点?你确定这不是将 PostgreSQL Interval 类型转换为 Java long 类型的“事情”吗?
  • @zbigniewTomczak 我通过修改 postgres 配置文件以使其记录完整请求(带有参数值)发现了这一点。我使用休眠 4.3.1.Final。我不使用 PostgreSQL 间隔。我给 2 Expression&lt;Date&gt; 并且 PostgreSQL 返回一个整数,表示日期之间的天数。我将?2 - ?1 更改为-?1 + ?2 并且成功了。
猜你喜欢
  • 2020-10-16
  • 1970-01-01
  • 1970-01-01
  • 2015-02-26
  • 2019-09-27
相关资源
最近更新 更多