Почему метод Timestamp.of() в java.sql неправильно преобразуется из LocalDateTime в java.time?

Я столкнулся с ошибкой, из-за которой java.sql

Timestamp.valueOf(LocalDateTime.MIN())

конвертирует неправильно.

Учитывая java.time

 LocalDateTime.MIN() = -999999999-01-01T00:00:00

Но когда я пытаюсь преобразовать его в дружественную к SQL метку времени, почему я сталкиваюсь с другим анализируемым временем, которое неправильно искажено?

Timestamp.valueOf(LocalDateTime.MIN()) = +169087565-03-15 04:51:43.000000

Я ожидал самую старую дату, но это выдает МАКС.

ПС:

Я работал над этим, используя

Timestamp.valueOf(//
        LocalDateTime.of(LocalDate.ofYearDay(1800,1), LocalTime.MIDNIGHT)

Как уже было сказано, вам следует придерживаться своего LocalDateTime, это все, что вам нужно. Избегайте java.sql.Timestamp, поскольку это был настоящий хак поверх и без того проблемного класса Date, который устарел с версии JDBC 4.2. В любом случае, ваш Timestamp, вероятно, был недостаточным, вы пытались присвоить ему значение, выходящее за пределы диапазона, который он может удерживать.

Anonymous 02.07.2024 05:53

Использование: в Timestamp.valueOf(LocalDateTime.MIN()) синтаксический анализ не выполняется. Это конверсия. (Парсинг — это анализ строки символов.)

Anonymous 02.07.2024 06:22

Нам это знать не обязательно, поскольку, как я уже сказал, нам не следует использовать Timestamp. Из любопытства только new Timestamp(Long.MIN_VALUE).toLocalDateTime() дает +292278994-08-17T08:12:55.192. Минимальное значение Timestamp кажется около 0001-01-01 00:00:00.0. Что, вероятно, соответствует диапазону, поддерживаемому многими вариантами SQL.

Anonymous 02.07.2024 06:38
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
98
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

вр; доктор

Никогда не используйте Timestamp.

Цель Джава JDBCСтандарт SQL Представляет момент, дату с временем суток в контексте часового пояса или смещения от UTC, конкретной точки на временной шкале. Instant, OffsetDateTime, ZonedDateTimejava.time.OffsetDateTimeTIMESTAMP WITH TIME ZONE Представляйте просто дату с указанием времени суток (а не момента). LocalDateTimejava.time.LocalDateTimeTIMESTAMP WITHOUT TIME ZONE

Избегайте java.sql.Timestamp

Вы сказали:

Дружественная к SQL отметка времени

Класс java.sql.Timestamp — один из ужасно ошибочных устаревших классов даты и времени, которые много лет назад были вытеснены современными классами java.time, определенными в JSR 310.

Используйте OffsetDateTime, а не Timestamp

JDBC 4.2 и более поздних версий требует, чтобы каждый драйвер JDBC поддерживал java.time. В частности, используйте OffsetDateTime вместо Timestamp.

Java предлагает три класса для представления момента: Instant, OffsetDateTime и ZonedDateTime. Но только OffsetDateTime сопоставляется с типом SQL в JDBC из-за ограничений стандарта SQL.

ЛокальныйДатаВремя

Класс LocalDateTime не может представлять момент, поскольку ему не хватает контекста часового пояса или смещения от UTC. Класс LocalDateTime представляет собой просто дату с указанием времени суток, не более того.

И устаревший тип Timestamp, и современный тип OffsetDateTime представляют собой момент, точку на временной шкале. Так что не стоит смешивать LocalDateTime с ними.

Избегайте минимумов и максимумов

.MIN

Избегайте использования крайних значений минимума/максимума. Системы баз данных различаются по своим ограничениям. Все, что мне известно, имеет гораздо меньший диапазон, чем java.time.

Если вам нужно какое-то значение сигнала для обозначения «старого», используйте более современное значение. Например, рассмотрим использование java.time.Instant.EPOCH, первого момента 1970 года в формате UTC, 1970-01-01T00:00Z.

OffsetDateTime epoch = Instant.EPOCH.atOffset( ZoneOffset.UTC ) ;

Я ожидал самую старую дату, но это выдает МАКС.

Вероятно, вы видите эффект переноса из-за целочисленного переполнения .

Внутренняя реализация Timestamp использует 32-битное целое число миллисекунд с момента ссылки на эпоху 1970-01-01T00:00Z, отрицательное до, положительное после. Классы java.time используют гораздо больший диапазон посредством двух счетчиков: 64-битное целое число целых секунд из той же ссылки на эпоху плюс дробная секунда, сохраняемая как счетчик наносекунд.

Но на самом деле нет смысла изучать этот вопрос. Нет смысла когда-либо использовать java.sql.Timestamp.

Конверсия

Если вам вручен Timestamp, немедленно преобразуйте, используя новые методы преобразования, добавленные к старым классам. В частности, java.time.Instant, затем назначьте смещение, чтобы получить SQL-дружественный OffsetDateTime объект.

Instant instant = myTimestamp.toInstant() ;  // A moment as seen in UTC, always UTC. 
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

Если вам нужен объект Timestamp для взаимодействия со старым кодом, еще не обновленным до java.time, конвертируйте.

java.sql.Timestamp ts = Timestamp.from( odt.toInstant() ) ;

Прямым эквивалентом JDBC java.sql.Timestamp является java.time.LocalDateTime (что иллюстрирует, почему тот факт, что он был основан на java.util.Date, был плохой идеей), как и для столбцов SQL TIMESTAMP [WITHOUT TIME ZONE], которые не содержат информации о часовом поясе и всегда интерпретируются в часовом поясе JVM по умолчанию для преобразование в java.sql.Timestamp, если только для их получения не используется один из методов с Calendar.

Mark Rotteveel 01.07.2024 18:55

Кроме того, вы утверждаете, что «только OffsetDateTime сопоставляется с типом SQL в JDBC», неверно. LocalDate сопоставляется с java.sql.Types.DATE (стандарт SQL DATE), LocalTime сопоставляется с TIME (стандарт SQL TIME [WITHOUT TIME ZONE]), LocalDateTime сопоставляется с TIMESTAMP (стандарт SQL TIMESTAMP [WITHOUT TIME ZONE], OffsetTime сопоставляется с TIME_WITH_TIMEZONE (стандарт SQL TIME WITH TIME ZONE) и OffsetDateTime сопоставляется с TIMESTAMP_WITH_TIMEZONE (SQL стандарт TIMESTAMP WITH TIME ZONE).

Mark Rotteveel 01.07.2024 18:59

Если базовым является TIMESTAMP, то переключение на использование OffsetDateTime не гарантированно будет работать, поскольку JDBC не определяет такое сопоставление. JDBC определяет только сопоставление с LocalDateTime, поэтому совместимый драйвер не может (и, что более важно, не должен, поскольку интерпретация/преобразование будет неоднозначным) поддерживать сопоставление с OffsetDateTime.

Mark Rotteveel 01.07.2024 19:06

Небольшое дополнение к моему второму комментарию: LocalDateTime также определено для DATE и TIME, по крайней мере, для setObject (см. таблицу B-5 в JDBC 4.3)

Mark Rotteveel 01.07.2024 19:09

Другие вопросы по теме

Как использовать индекс, если искомый столбец не индексирован, но имеет тот же порядок, что и индексированный первичный ключ
Как получить информацию о самоанализе движка SQLite через Rust SQLx?
Отобразить среднее количество дней между последней и предпоследней транзакцией клиента
Как запросить фрейм данных Snowpark с помощью SQL из Snowflake?
Как устранить ошибку «Ошибка компиляции SQL: объект SNOWPARK_TEMP_STAGE_FLGVIWVUC уже существует». проблема в снежинке?
Как объединить две или более строк и СУММИРОВАТЬ столбец в ОБНОВЛЕНИИ без первичного ключа?
Левая часть выражения LIKE должна иметь значение varchar (фактически: varbinary). Какая альтернатива преобразованию varbinary в varchar?
Чтобы получить предыдущую запись, которая меньше заданной даты и времени
Выберите строки с тем же кодом товара, но с другим значением в другом столбце
Извлечение и обработка подстроки между различным количеством разделителей в строке переменной длины