Почему запрос даты до нашей эры меняется на AD в Java?

Моя программа на Java подключается к базе данных (Oracle XE 11g), которая содержит много дат (формат даты OracleXE установлен на syyyy/mm/dd).

Выполнение запроса в базе данных с отрицательными датами (до Христа) работает нормально. Когда я делаю это на Java, все они меняются на AD (Anno Domini). Как я могу получить даты в Java с учетом AD/BC?

Мой Java-код здесь выполняет запрос к БД и помещает результат в таблицу.

try {
    Object item=cbPD.getSelectedItem();                                 
    String dacercare=item.toString();
    query = "SELECT DISTINCT PD.Titolo,PD.Inizio,(Select E.nome From Evento E WHERE PD.Inizio_Evento=E.CODE),
            PD.Fine, (Select E.nome From Evento E  WHERE PD.Fine_Evento=E.CODE ) FROM Periododelimitato PD WHERE PD.Titolo=?";
    PreparedStatement stAccess = Login.connessione.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
    stAccess.setString(1,dacercare);
    rset = stAccess.executeQuery(); 
    j = modelPD.getRowCount();
    for (i=0; i<j; i++) modelPD.removeRow(0);
    Date data;
    while (rset.next()) {
        data = rset.getDate(2);
        modelPD.addRow(new Object[]{rset.getString(1),data, rset.getString(3), rset.getString(4), rset.getString(5)});
    }       
}

Вот Пример использования определенного запроса:

try {
    query = "SELECT PD.Inizio FROM PeriodoDelimitato PD WHERE PD.CodP=?";
    String dacercare="8"; //look for record with this specific Primary key
    PreparedStatement stAccess = Login.connessione.prepareStatement(query,
            ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
    stAccess.setString(1, dacercare);
    rset = stAccess.executeQuery(); 
    while(rset.next()) {
        Date dateBC = rset.getDate(1);
        modelPD.addRow(new Object[]{null, dateBC, null, null, null});
    }

Вывод в Java:

0509-01-01

Вывод с использованием того же запроса (заменив ? на указанный первичный ключ) в разработчике Sql:

-0509/01/01

Примечание к запросу: столбец, выбранный в этом примере, имеет в Oracle тип DATE.

Добавление информации: СУБД — Oracle (XE 11g), БД построена на IDE (разработчик SQL). Программа написана на Java через Netbeans 8.2. Я подключаюсь к базе данных в Netbeans, добавляя библиотеку «ojdbc6.jar».


person StefanoF    schedule 19.10.2017    source источник
comment
Проверьте, является ли ваш драйвер JDBC 4.2 (или выше), и попробуйте использовать getObject(2, LocalDateTime.class). java.sql.Date основано на миллисекундах с 01.01.1970.   -  person Mark Rotteveel    schedule 19.10.2017
comment
Почему вы используете ojdbc6.jar? Вы действительно работаете на Java 6?   -  person Andreas    schedule 19.10.2017
comment
@MarkRotteveel для версии JDBC Версия драйвера: 11.2.0.4.0, я не понял, как использовать getObject в моем случае, можете ли вы объяснить это?   -  person StefanoF    schedule 19.10.2017
comment
Учитель @Andreas сказал использовать его, может ли это вызвать проблему?   -  person StefanoF    schedule 19.10.2017
comment
Не могли бы вы правильно сделать отступ в коде и разбить строки, чтобы не так много кода исчезало за кадром справа? Заранее спасибо.   -  person Ole V.V.    schedule 19.10.2017
comment
Кроме того, возможно, вы можете воспроизвести свою проблему, используя более простой запрос? См. раздел Как создать минимальный, полный и проверяемый пример.   -  person Ole V.V.    schedule 19.10.2017
comment
@ОлеВ.В. Я добавил более простой пример с простым запросом для указанного ПК. Я тоже пытался ломать линии, надеюсь, теперь это лучше. Спасибо за терпение   -  person StefanoF    schedule 19.10.2017
comment
MCVE будет всем SQL, необходимым для создания небольшой таблицы с наименьшим количеством полей, добавления нескольких записей и выполнения запроса, игнорируя при этом все другие детали бизнес-проблемы.   -  person Basil Bourque    schedule 19.10.2017
comment
Каков тип данных столбца даты в Oracle?   -  person Basil Bourque    schedule 19.10.2017
comment
@BasilBourque тип столбца, выбранного в примере запроса, - DATE в Oracle.   -  person StefanoF    schedule 19.10.2017
comment
@StefanoF Публикуйте дополнительные сведения как правки к Вопросу, а не как комментарии.   -  person Basil Bourque    schedule 19.10.2017
comment
@BasilBourque Отредактировано, спасибо, надеюсь, теперь это лучше объяснено   -  person StefanoF    schedule 19.10.2017
comment
Можете ли вы извлечь номер года из полученного объекта даты, чтобы определить, является ли это проблемой форматирования или проблемой ошибочных данных?   -  person Basil Bourque    schedule 20.10.2017
comment
Кстати, имейте в виду, что вам не рекомендуется использовать java.sql.Date или java.util.Date. Эти неприятные старые классы теперь заменены классами java.time.   -  person Basil Bourque    schedule 20.10.2017
comment
Спасибо, что последовали нашим предложениям, @StefanoF. Это значительно улучшило вопрос. Я считаю, что еще больше улучшил отступ вашего кода.   -  person Ole V.V.    schedule 20.10.2017


Ответы (2)


Во-первых, не сразу понятно, как следует обращаться с историческими и, не в последнюю очередь, с доисторическими датами и как следует ожидать их поведения. Я не знаю этого, но я сомневаюсь, что какой-либо широко используемый сегодня календарь использовался в 6 веке до нашей эры (до нашей эры, «до нашей эры»). Возможно, вы уже знали, я просто хотел упомянуть об этом для всех, кто читает этот ответ.

Благодаря ответу Бэзила Бурка (теперь удаленному) то, что вы заметили, похоже, является предполагаемым поведением с java.sql.Date. Я попытался напечатать даты со 2 года н.э. (нашей эры, «н.э.»), а затем со 2 года до н.э. и сравнил. Первые 2 CE:

    LocalDate ld = LocalDate.of(2, 1, 1);
    java.sql.Date sqlDate = java.sql.Date.valueOf(ld);
    System.out.println("java.sql.Date " + sqlDate + " millis " + sqlDate.getTime());

java.sql.Date 0002-01-01 миллис-62104237200000

Это ожидаемо. Для 2 BCE нам нужно указать от -1 до LocalDate, поскольку 0 означает 1 BCE, а -1 означает 2 BCE. Вставьте LocalDate.of(-1, 1, 1) в приведенный выше код, и вывод будет

java.sql.Date 0002-01-01 миллис-62198931600000

Отметим, что дата печатается одинаково. Число 0002 едва ли можно назвать абсолютно неверным, но оно не говорит нам, идет ли речь о втором году нашей эры или о втором году нашей эры. Я считаю, что это объясняет поведение, которое вы наблюдали. Далее мы отмечаем, что значения миллисекунд разные, поэтому даты отличаются, как и должно быть. Разница составляет 94694400000 миллисекунд, что равняется 1096 дням или 3 годам, если один из них високосный. Високосный год может удивить, но в остальном я думаю, что это правильно.

Хотя есть что-то рыбное. Когда я преобразовал дату sql обратно в LocalDate, эра была потеряна, я всегда получал дату в общей эре. Поскольку вам не нужно это преобразование, вам, вероятно, не нужно заботиться.

Я считаю, что хорошим решением будет полный отказ от устаревшего класса Date и повсеместное использование современного LocalDate. Вы должны знать, что это соответствует так называемому пролептическому григорианскому календарю, который не всегда может дать те же даты, что и Date. Также для этого требуется драйвер, совместимый с JDBC 4.2, поэтому ваш ojdbc6.jar не подойдет. Даже если это может означать, что вы помешали, я оставлю это предложение в силе для всех, кто читает дальше. Я не проверял, но думаю, что должно работать следующее:

LocalDate dateBC = rset.getObject(1, LocalDate.class);
person Ole V.V.    schedule 20.10.2017
comment
Спасибо за ваше время, я нашел решение, которое работает с ojdbc6.jar, если бы оно не сработало, я думаю, я бы последовал вашему предложению, чтобы отказаться от старой библиотеки, поговорив с учителем. - person StefanoF; 20.10.2017

Решение, использующее старый тип Date для запроса дат SQL BC и AC, которое работает, состоит в том, чтобы объявить в моем классе SimpleDataFormat с форматом, указанным ниже.

public SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd G");

Затем я объявил Date dataOUT, вызвав метод форматирования SimpleDataFormat, предоставив в качестве входных данных дату BC, запрошенную из базы данных.

dataOUT=sdf.format(rset.getDate(2));

Спасибо всем за время, уделенное моему вопросу!

person StefanoF    schedule 20.10.2017
comment
Спасибо, что поделились своим решением. Настаивая на старых классах, это решение является правильным и даст результат, подобный 0509-01-01 BC. Я по-прежнему рекомендую современный API. :-) - person Ole V.V.; 20.10.2017