【问题标题】:Date difference in date in Oracle and JavaOracle 和 Java 中日期的日期差异
【发布时间】:2010-06-23 09:14:57
【问题描述】:

以下问题困扰着我,我找不到任何合理的解释和解决方案。也许有人可以启发我。

我有一个计算日期差异(以天为单位)的应用程序 - 在搜索掩码和详细信息掩码中。在第一个掩码中,我使用 days 过滤出具有持续时间搜索条件(搜索掩码)的记录,并使用 SQL 查询来执行此操作:

WHERE...
...
AND DECODE(TRUNC(to_number(SUBSTR((close_date - 
create_date),1,instr(close_date - create_date,' ')))), NULL, 
TRUNC(to_number(SUBSTR((systimestamp - create_date),1,instr(systimestamp - 
create_date,' ')))), TRUNC(to_number(SUBSTR((close_date - 
create_date),1,instr(close_date - create_date,' ')))) ) >=140

AND DECODE(TRUNC(to_number(SUBSTR((close_date - 
create_date),1,instr(close_date - create_date,' ')))), NULL, 
TRUNC(to_number(SUBSTR((systimestamp - create_date),1,instr(systimestamp - 
create_date,' ')))), TRUNC(to_number(SUBSTR((close_date - 
create_date),1,instr(close_date - create_date,' ')))) ) <=140

在这种特殊情况下,我尝试找出所有持续时间为 140 天的记录。

在第二个掩码(详细信息)中,我显示了记录详细信息,包括其持续时间。这是通过以下 java 代码完成的:

public static Integer getDuration(Date caseDate, Date closeDate) {
    Date beginDate = caseDate;
    Date endDate = (closeDate != null)? closeDate: new Date();

    long difference = endDate.getTime() - beginDate.getTime();   
    int daysDiff = (int) (difference / (24.0 * 60 * 60 * 1000));  
    return new Integer(daysDiff);
}

我的问题是,当我搜索时,我找到了一些符合搜索条件的记录。例如,我找到 4 条记录,所有记录的持续时间均为 140 天。这是甲骨文的说法。但是,当我为其中一些人打开详细信息蒙版时,我会得到 139 天的持续时间。所以不知何故,Java 和 Oracle 以不同的方式计算日期差异。似乎在 Oracle 中进行了一些舍入,但我找不到发生这种情况的地方。因此,任何建议都会有所帮助。谢谢!

您好, 历历在目

【问题讨论】:

  • 在Oracle中没有更优雅的计算差异的方法吗?难道你不能完全按照你在 Java 中所做的:将日期相减吗?
  • 这几乎是我认为最优雅的方式。当我减去时,我得到类似 140 0:0:0.0 或 140 10:13:15.54734 的结果。 substr-part 仅用于从结果中提取天数。
  • 您能给我们举一个 Oracle 和 Java 评估不同的日期的例子吗?可能会帮助我们确定它。
  • create_date - 11.02.09 00:00:00,000000000 close_date - 01.07.09 00:00:00,000000000 系统时间戳 - 23.06.10 14:05:35,927570000 +02:00跨度>

标签: java oracle datetime


【解决方案1】:

日期可能相同,但时间可能不同。当您以毫秒计算时,结果为 139 天。 (java)

我建议不要使用millis,而是使用天数来计算。

类似

public long daysBetween(Calendar startDate, Calendar endDate) {
   Calendar date = (Calendar) startDate.clone();
   long daysBetween = 0;
   while (date.before(endDate)) {
      date.add(Calendar.DAY_OF_MONTH, 1);
      daysBetween++;
   }}

/**
     *
     * @param c1 from
     * @param c2 to
     * @return amount of days between from and to
     */
    public int diff(Calendar c1, Calendar c2) {
        int years = c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR);
        if (years == 0) {
            return c2.get(Calendar.DAY_OF_YEAR) - c1.get(Calendar.DAY_OF_YEAR);
        } else {
            Calendar endOfYear =  Calendar.getInstance();
            endOfYear.set(Calendar.YEAR, c1.get(Calendar.YEAR));
            endOfYear.set(Calendar.MONTH, 11);
            endOfYear.set(Calendar.DAY_OF_MONTH, 31);
            int days = endOfYear.get(Calendar.DAY_OF_YEAR) - c1.get(Calendar.DAY_OF_YEAR);
            for (int i=1;i <years;i++) {
                endOfYear.add(Calendar.YEAR, 1);
                days += endOfYear.get(Calendar.DAY_OF_YEAR);
            }
            days += c2.get(Calendar.DAY_OF_YEAR);
            return days;
        }
    }

旁注: 第一个例子比第二个稍微慢一点,但如果只是为了小的差异,它可以忽略不计。

【讨论】:

【解决方案2】:

我以同样的方式计算,但我使用 dayDiff,只要不是整数。所以也试试,不要投。它应该可以正常工作。

【讨论】:

  • 我不太明白你的评论。这将如何影响“差异”?
  • 不会,只有当计算结果高于 Integer.MAX_VALUE 时
  • 好吧,我不确定。我刚刚检查了我的来源,它就是这样工作的:O 无论如何,日历解决方案胜出!
  • 我还没有尝试过日历解决方案。然而,我尝试过的是在 Java 中把日子变成双倍。结果是 - 139.95833333333334。所以发生的事情,在我看来是,演员是罪魁祸首。你怎么看?
  • 那些毫秒是危险的 :D 但是,139.9583 仍然不是 140。所以 java 不应该是错的,Oracle 应该是。或者试试那个日历解决方案,它更干净,你会看到结果。
【解决方案3】:

这里的问题是您认为两列都是 DATE 列,其中至少两列中的一个实际上是 TIMESTAMP 列。当您从另一个日期中提取一个日期时,您会得到一个 NUMBER。但是,当您从时间戳中提取日期(反之亦然)时,您会得到一个 INTERVAL。

一个例子

带有 DATE 和 TIMESTAMP 的表:

SQL> create table mytable (close_date,create_date)
  2  as
  3  select date '2010-11-01', systimestamp from dual union all
  4  select date '2010-11-11', systimestamp from dual union all
  5  select date '2010-12-01', systimestamp from dual
  6  /

Table created.

SQL> desc mytable
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 CLOSE_DATE                                         DATE
 CREATE_DATE                                        TIMESTAMP(6) WITH TIME ZONE

从 DATE 列中提取一个 TIMESTAMP,导致一个 INTERVAL:

SQL> select close_date - create_date
  2    from mytable
  3  /

CLOSE_DATE-CREATE_DATE
---------------------------------------------------------------------------
+000000130 11:20:11.672623
+000000140 11:20:11.672623
+000000160 11:20:11.672623

3 rows selected.

而且没有必要摆弄 TO_NUMBER 和 SUBSTR。只需使用 EXTRACT 函数从区间中获取您想要的组件:

SQL> select extract(day from (close_date - create_date))
  2    from mytable
  3  /

EXTRACT(DAYFROM(CLOSE_DATE-CREATE_DATE))
----------------------------------------
                                     130
                                     140
                                     160

3 rows selected.

问候, 抢。

这是一个带有两个 TIMESTAMPS 的示例,它表明 INTERVAL 被截断,而不是四舍五入:

SQL> create table mytable (close_date,create_date)
  2  as
  3  select to_timestamp('2010-11-01','yyyy-mm-dd'), trunc(systimestamp,'dd') + interval '6' hour from dual union all
  4  select to_timestamp('2010-11-11','yyyy-mm-dd'), trunc(systimestamp,'dd') + interval '12' hour from dual union all
  5  select to_timestamp('2010-12-01','yyyy-mm-dd'), trunc(systimestamp,'dd') + interval '18' hour from dual
  6  /

Table created.

SQL> desc mytable
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 CLOSE_DATE                                         TIMESTAMP(9)
 CREATE_DATE                                        DATE

SQL> select close_date - create_date
  2    from mytable
  3  /

CLOSE_DATE-CREATE_DATE
---------------------------------------------------------------------------
+000000130 18:00:00.000000000
+000000140 12:00:00.000000000
+000000160 06:00:00.000000000

3 rows selected.

SQL> select extract(day from (close_date - create_date))
  2    from mytable
  3  /

EXTRACT(DAYFROM(CLOSE_DATE-CREATE_DATE))
----------------------------------------
                                     130
                                     140
                                     160

3 rows selected.

【讨论】:

  • 我已经检查过了,两者都是时间戳列 - close_date 和 create_date。我也使用了提取功能。这并不影响结果。我怀疑是甲骨文做了一些四舍五入的日子。
  • 我刚刚检查了两个TIMESTAMPS,结果还是一样的。 Oracle 不会舍入日期,它会在使用 EXTRACT 函数时截断它。查看更新的答案。
  • 是的,这也是我昨天的结果。这似乎也是现在的问题,因为日历解决方案似乎正在结束日子。所以现在我得到了 141 天的结果,当我用 140 进行搜索时。
猜你喜欢
  • 2014-04-05
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-01
  • 2015-10-08
  • 1970-01-01
  • 2011-11-02
相关资源
最近更新 更多