Разница в дате в Oracle и Java - PullRequest
1 голос
/ 23 июня 2010

следующая проблема беспокоит меня, и я не могу найти разумного объяснения и решения. Возможно, кто-то мог бы просветить меня.

У меня есть приложение, которое вычисляет разницу дат (в днях) - в маске поиска и в маске деталей. В первой маске я использую дни, чтобы отфильтровать записи с критериями поиска по продолжительности (маска поиска), и я делаю это с помощью запроса 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 дней. Это в соответствии с Oracle. Но когда я открываю маску Details для некоторых из них, я получаю продолжительность, например, 139 дней. Так что Java и Oracle каким-то образом рассчитывают разницу в датах по-разному. Похоже, что в Oracle происходит некоторое округление, но я не могу найти, где это происходит. Так что любые предложения будут полезны. Спасибо!

Поздравил, Алмаак

Ответы [ 3 ]

3 голосов
/ 23 июня 2010

Дата может быть одинаковой, но время может быть другим. Получается 139 дней при подсчете через миллисекунды. (Java)

Я предлагаю не использовать миллис, а использовать дни для расчета.

Что-то вроде

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

Примечание: Первый пример немного медленнее второго, но если он только для небольших различий, он пренебрежимо мал.

1 голос
/ 23 июня 2010

Проблема здесь в том, что вы думаете, что оба столбца являются столбцами DATE, где хотя бы один из этих двух столбцов действительно является столбцом TIMESTAMP.Когда вы извлекаете одну дату из другой, вы получаете НОМЕР.Но когда вы извлекаете дату из отметки времени или наоборот, вы получаете ИНТЕРВАЛ.

Пример

Таблица с 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

Извлечение TIMESTAMP из столбца DATE приводит к ИНТЕРВАЛУ:

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.
1 голос
/ 23 июня 2010

Я рассчитал таким же образом, но я использовал dayDiff до тех пор, пока не целое число. Так что попробуй и не бросай. Должно работать нормально.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...