Почему JPA не поддерживает java.time.Instant?

Я думаю, что java.time.Instant - лучший выбор для хранения даты в БД: это наиболее вероятный TIMESTAMP, и вы не зависите от часового пояса, это просто момент времени.

JPA поддерживает LocalDate, LocalTime, LocalDateTime и т. д., но не Instant. Конечно, вы можете использовать либо AttributeConverter, либо некоторые библиотеки, такие как Jadira, но почему это не поддерживается по умолчанию?


person Filosssof    schedule 15.03.2018    source источник
comment
Обратите внимание, что он поддерживается в Hibernate 5.   -  person chrylis -cautiouslyoptimistic-    schedule 16.03.2018
comment
Я знаю. Но сегодня в обсуждении с коллегами возникла идея, что не стоит использовать Instant, потому что JPA его не поддерживает. И я хочу знать, почему?   -  person Filosssof    schedule 16.03.2018
comment
DataNucleus JPA поддерживает его еще до Java 8! Простой факт заключается в том, что Oracle обленился с JPA API и не мог побеспокоиться о выделении ресурсов для него, поэтому в JPA 2.2 было очень мало элементов, и это тип, который они упустили.   -  person    schedule 16.03.2018
comment
RE: ваше первое предложение: (a) Да, используйте java.time.Instant для представления момента, например столбец TIMESTAMP WITH TIME ZONE стандарта SQL. И да, Instant заменяет классы java.util.Date и java.sql.Timestamp. (б) Нет, «не зависит от часового пояса» неверно. Есть часовой пояс, связанный с Instant: UTC. Что касается базы данных, это поведение варьируется. Например, в Postgres ввод в столбец TIMESTAMP WITH TIME ZONE использует любую предоставленную информацию о зоне/смещении для настройки в формате UTC для хранения, а затем отбрасывает предоставленную информацию о зоне/смещении после завершения настройки.   -  person Basil Bourque    schedule 18.03.2018
comment
Не обращайте внимания на неверные советы по использованию java.time.LocalDateTime на этой странице и в других местах. Этот класс не представляет момент, поскольку в нем намеренно отсутствует какое-либо понятие зоны/смещения. Этот класс является неопределенным и представляет приблизительное представление о потенциальных моментах в диапазоне примерно 26–27 часов (диапазон часовых поясов по всему миру).   -  person Basil Bourque    schedule 18.03.2018


Ответы (2)


Я попробую это снова. В этой проблеме есть обсуждение. Последнее обсуждение выглядит следующим образом:

mkarg сказал: Хотя это абсолютно правильно, технический ответ немного сложнее: какой последний предикат делает тип данных пригодным для включения в набор обязательных сопоставлений типов?

Можно было бы сказать, что этот предикат — «существенный» или «общеупотребительный», но кто определяет, что такое «существенный» или «общеупотребительный»? Видите ли, для некоторых приложений поддержка java.awt.Image и java.net.URL может быть гораздо важнее, чем поддержка LocalDate или ZonedDateTime. С другой стороны, другие приложения могут быть заполнены LocalDate, но никогда не использовать Instant. Так где именно делать разрез? Это становится особенно сложным, если посмотреть на огромное количество типов, найденных в JRE, и становится очевидным, что где-то должен быть вырез. Даже JavaFX, который связан с JRE, не поддерживает Instant еще в v8, так зачем JPA? И, глядя на текущий прогресс Project Jigsaw, возможно, на определяющий предикат можно просто ответить «все типы в конкретном модуле головоломки»?

В любом случае решать не мне. Я поддерживаю ваш запрос и хотел бы видеть поддержку для всех времен API Java Time, особенно для Instant и Duration, и у вашего запроса есть известные сторонники, такие как, например, Java Champion Арун Гупа, как я узнал недавно. Но я сомневаюсь, что окончательный ответ будет таким же простым и удовлетворительным, как нам бы хотелось его получить.

Возможно, было бы лучше просто настроить другой JSR, например «Общие преобразования типов данных для платформы Java», который обеспечивает гораздо больше сопоставлений, чем просто дата и время, но также не будет привязан к JPA, но также может использоваться JAXB , JAX-RS и, возможно, другие API, которые решают проблему преобразования "в"? Наличие такого транспортного средства действительно значительно уменьшит количество шаблонов.

TL-DR; Есть много типов. Нам нужно было где-то провести черту.

Существует новая проблема, которая будет добавлена ​​в будущую версию JPA. .

Еще один интересный фрагмент анализа, который я нашел в ветке от Douglas Surber (работает на JDBC):

Версия JDK 8 JDBC включает поддержку большинства типов SQL, соответствующих классам 310.

  • ДАТА – местная дата
  • ВРЕМЯ – местное время
  • TIMESTAMP БЕЗ ЧАСОВОГО ПОЯСА — LocalDateTime
  • TIMESTAMP С ЧАСОВЫМ ПОЯСОМ – OffsetDateTime

Версия JDK 8 JDBC не включает сопоставление между типами INTERVAL и соответствующими классами 310.

Не существует типа SQL, точно соответствующего любому другому классу 310. В результате спецификация JDBC ничего не говорит обо всех остальных классах.

Я бы настоятельно рекомендовал разработчикам JDBC использовать новые классы 310. Существуют проблемы с java.util.Date, java.sql.Date, java.sql.Time и java.sql.Timestamp. Вы должны считать их устаревшими. Классы 310 намного лучше.

Дуглас

TL:DR; Мы только что выбрали один тип Java 8 для каждого из 4 возможных способов хранения временных данных в базе данных.

Наконец, если вы прочитаете эту thread похоже, существует значительное культурное давление, чтобы стандартные API были маленькими и простыми.

person Pace    schedule 15.03.2018
comment
Для меня хранение LocalDate (LocalTime, LocalDateTime) не является хорошим способом, потому что они используют TimeZone, но не сохраняют его, поэтому ваше приложение должно использоваться в одном TimeZone, или вы должны хранить часовой пояс в другом столбце или (я думаю наиболее часто используемый случай) сохраните эту дату в формате UTC и при каждом запросе преобразуйте ее в нужный часовой пояс. - person Filosssof; 16.03.2018
comment
Если вам нужно сохранить часовой пояс, используйте OffsetDateTime. - person Pace; 16.03.2018
comment
Проблема в том, что мне не нужен конкретный TimeZone, TimeZone я получу из браузера и адаптирую Instant к нужному TimeZone. - person Filosssof; 16.03.2018
comment
Ok. Я прочитал твой комментарий задом наперёд. Если вы хотите хранить все свое время в формате UTC, просто выполните LocalDateTime.ofInstant(instant, ZoneOffset.UTC); - person Pace; 16.03.2018
comment
Извращенно это на самом деле более гибко, чем Instant, потому что, если в вашей базе данных уже было много существующих данных (или другое приложение создавало данные), которые хранились в виде метки времени без часового пояса, но не в формате UTC, тогда JPA не знал бы как сопоставить это с мгновением. Таким образом, если вы сопоставляете столбец, в котором нет информации о часовом поясе, вам необходимо указать часовой пояс, в котором были сохранены данные. - person Pace; 16.03.2018
comment
Это не новая проблема, о которой вы говорите. Это старая проблема, которая требовала поддержки ВСЕХ разумных типов java.time, и, как видно, представитель Oracle в одностороннем порядке решил, что он будет поддерживать только подмножество в спецификации JPA 2.2. Новая проблема — это github.com/javaee/jpa-spec/issues/163< /а> - person ; 16.03.2018
comment
Они нарисовали линию не в том месте. Класс java.time по умолчанию теперь Instant, все остальные являются дополнительными. Поэтому, если бы им пришлось подвести черту, они бы использовали только Instant, а затем добавили другие. - person Krzysztof Krasoń; 31.03.2021

Это не проблема JPA, а проблема JDBC.

JDBC поддерживает Date, Timestamp, LocalDate, LocalTime и LocalDateTime, но НЕ Instant.

Это не проблема Java, а проблема SQL, из-за которой в базе данных хранится конструкция год-месяц-день-час-минута-секунда.

Подумайте о функциях SQL: ГОД() МЕСЯЦ() и т.д...

Эти функции нельзя применять к простым миллисенкодам с номера 1970. Для выполнения этих функций им требуется конструкция LocalDateTime.

person klonq    schedule 18.03.2018
comment
Этот ответ совершенно неверен. (A) JDBC 4.2 и более поздние версии поддерживают java.time: см. методы PreparedStatement::setObject и ResultSet::getObject. Эта поддержка включает Instant. (B) LocalDateTime — это точно неправильный класс, поскольку в нем отсутствует какое-либо понятие часового пояса или смещения от UTC. Таким образом, LocalDateTime не представляет момент, не точку на временной шкале и не может использоваться для представления числа, которое является отсчетом от 1970-01-01T00. :00Z отсылка к эпохе. - person Basil Bourque; 18.03.2018
comment
(C) Это это проблема JPA. Hibernate уже поддерживает java.time включая Instant. Судя по моему ограниченному чтению (я не пользователь), похоже, проблема в том, что люди, ответственные за JPA, ленивы или некомпетентны. - person Basil Bourque; 18.03.2018
comment
@Basil Bourque Есть люди, которые так думают (о лени или некомпетентности), но в этом случае самый простой способ - реализовать Instant - который является TIMESTAMP и не тратить время на LocalDate, LocalTime и т. д. - person Filosssof; 18.03.2018
comment
@Filosssof Да, в качестве обходного пути вам может понадобиться использовать java.sql.Timestamp. Но немедленно преобразуйте в классы java.time, вызвав новые методы преобразования, добавленные к старым устаревшим классам даты и времени: Instant instant = myJavaSqlTimestamp.toInstant() ;. Эти устаревшие классы даты и времени представляют собой жалкий беспорядок из-за плохого дизайна и хаков — избегайте / минимизируйте их использование. Фреймворк java.time был создан для замены этих старых классов по многим веским причинам. - person Basil Bourque; 18.03.2018