java.util.Date vs java.sql.Date - PullRequest
       31

java.util.Date vs java.sql.Date

477 голосов
/ 21 февраля 2010

java.util.Date против java.sql.Date: когда и какие использовать и почему?

Ответы [ 5 ]

563 голосов
/ 21 февраля 2010

Поздравляем, вы ударили мою любимую мозоль с JDBC: обработка класса Date.

Обычно базы данных поддерживают как минимум три формы полей даты и времени, которые представляют собой дату, время и метку времени. Каждый из них имеет соответствующий класс в JDBC и каждый из них расширяется java.util.Date. Быстрая семантика каждого из этих трех:

  • java.sql.Date соответствует SQL DATE, что означает, что он хранит годы, месяцы и дни , тогда как часы, минуты, секунды и миллисекунды игнорируются. Дополнительно sql.Date не привязан к часовым поясам.
  • java.sql.Time соответствует времени SQL и, как должно быть очевидно, содержит только информацию о часах, минутах, секундах и миллисекундах .
  • java.sql.Timestamp соответствует SQL TIMESTAMP, который является точной датой наносекунды ( обратите внимание, что util.Date поддерживает только миллисекунды! ) с настраиваемой точностью.

Одна из наиболее распространенных ошибок при использовании драйверов JDBC в отношении этих трех типов заключается в том, что типы обрабатываются неправильно. Это означает, что sql.Date зависит от часового пояса, sql.Time содержит текущий год, месяц и день и так далее и тому подобное.

Наконец: какой использовать?

Действительно зависит от типа поля SQL. PreparedStatement имеет сеттеры для всех трех значений, #setDate() - один для sql.Date, #setTime() для sql.Time и #setTimestamp() для sql.Timestamp.

Обратите внимание, что если вы используете ps.setObject(fieldIndex, utilDateObject);, вы на самом деле можете дать обычное util.Date большинству драйверов JDBC, которые с радостью пожрут его, как если бы он был правильного типа, но когда вы запросите данные впоследствии, вы можете заметить, что вы на самом деле скучаете.

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

То, что я говорю, сохраняйте миллисекунды / наносекунды в виде простых длинных и конвертируйте их в любые объекты, которые вы используете ( обязательный штекер времени joda ). Один хакерский способ, который можно сделать, - это сохранить компонент даты как один компонент времени и времени как другой, например, прямо сейчас будет 20100221 и 154536123. Эти магические числа можно использовать в запросах SQL и переносить из базы данных в другую и позволит вам полностью отказаться от этой части JDBC / Java Date API:

57 голосов
/ 21 февраля 2010

ПОЗДНЕЕ РЕДАКТИРОВАНИЕ: Начиная с Java 8, вы не должны использовать ни java.util.Date, ни java.sql.Date, если вообще можете этого избежать, а вместо этого предпочитаете использовать пакет java.time (на основе Йода), а не что-нибудь еще. Если вы не на Java 8, вот оригинальный ответ:


java.sql.Date - при вызове методов / конструкторов библиотек, которые его используют (например, JDBC). Не иначе. Вы не хотите вводить зависимости в библиотеки баз данных для приложений / модулей, которые не имеют явного отношения к JDBC.

java.util.Date - при использовании библиотек, которые его используют. В противном случае, как можно меньше, по нескольким причинам:

  • Это изменчиво, что означает, что вы должны делать защитную копию каждый раз, когда передаете или возвращаете из метода.

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

  • Теперь, поскольку j.u.D не очень хорошо справляется со своей работой, были введены ужасные классы Calendar. Они также изменчивы и с ними ужасно работать, и их следует избегать, если у вас нет выбора.

  • Существуют лучшие альтернативы, такие как Joda Time API (, которые могут даже превратиться в Java 7 и стать новым официальным API для обработки дат - быстрый поиск говорит, что не будет).

Если вы чувствуете, что вводить новую зависимость, например Joda, излишне, long не так уж и плохо использовать для полей отметок времени в объектах, хотя я сам обычно оборачиваю их в juD при передаче их для безопасности типов и как документация.

19 голосов
/ 21 февраля 2010

Единственное время для использования java.sql.Date находится в PreparedStatement.setDate. В противном случае используйте java.util.Date. Это говорит о том, что ResultSet.getDate возвращает java.sql.Date, но его можно назначить непосредственно java.util.Date.

10 голосов
/ 17 июля 2014

У меня была та же проблема, самый простой способ вставить текущую дату в подготовленное утверждение - это:

preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
2 голосов
/ 22 ноября 2013

Класс java.util.Date в Java представляет определенный момент времени (например, .g., 2013 25 ноября 16:30:45 вплоть до миллисекунд), но тип данных DATE в БД представляет только дату (например, 2013 ноябрь 25). Чтобы вы не могли ошибочно предоставить объект java.util.Date в БД, Java не позволяет напрямую устанавливать параметр SQL в java.util.Date:

PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, d); //will not work

Но это все же позволяет вам делать это принудительно / намеренно (тогда часы и минуты будут игнорироваться драйвером БД). Это делается с помощью класса java.sql.Date:

PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, new java.sql.Date(d.getTime())); //will work

Объект java.sql.Date может хранить момент времени (так что его легко построить из java.util.Date), но выдает исключение, если вы попытаетесь задать его часами (для реализации его концепции быть только на свидании). Ожидается, что драйвер БД распознает этот класс и просто использует 0 для часов. Попробуйте это:

public static void main(String[] args) {
  java.util.Date d1 = new java.util.Date(12345);//ms since 1970 Jan 1 midnight
  java.sql.Date d2 = new java.sql.Date(12345);
  System.out.println(d1.getHours());
  System.out.println(d2.getHours());
}
...