java.util.Date vs java.sql.Date

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

вопрос задан 21.02.2010
flybywire
91163 репутация

5 ответов


  • 543 рейтинг

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

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

    • java.sql.Date соответствует SQL DATE, что означает, что он хранит года, месяца и дня , в то время как часа, минуты, секунды и миллисекунды игнорируются. Кроме того, sql.Date не привязан к часовым поясам.
    • java.sql.Time соответствует SQL TIME и, как должно быть очевидно, содержит только информацию о часах, минутах, секундах и миллисекундах .
    • 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.

    ответ дан Esko, с репутацией 22973, 21.02.2010
  • 52 рейтинг

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


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

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

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

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

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

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

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

    ответ дан gustafc, с репутацией 22741, 21.02.2010
  • 17 рейтинг

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

    ответ дан Paul Tomblin, с репутацией 136448, 21.02.2010
  • 10 рейтинг

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

    preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
    
    ответ дан Israelm, с репутацией 885, 16.07.2014
  • 2 рейтинг

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

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

    Но это все же позволяет вам делать это принудительно / намеренно (тогда часы и минуты будут игнорироваться драйвером БД). Это сделано с Java. SQL. Класс даты:

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

    Ява. SQL. Объект Date может хранить момент времени (так что его легко построить из Java). Util. Дата), но выдаст исключение, если вы попытаетесь спросить его о часах (чтобы обеспечить концепцию только даты). Ожидается, что драйвер БД распознает этот класс и просто использует 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());
    }
    
    ответ дан Kent Tong, с репутацией 49, 22.11.2013