tl; dr
Вы смешиваете неправильные типы данных в вашей базе данных и в Java-коде, пытаясь представить момент, отбрасывая важную информацию о зоне / смещении.Но если вы настаиваете:
myPreparedStatement.setObject (
… ,
OffsetDateTime.now( ZoneOffset.UTC ).toLocalDateTime() // Or some other `ZoneId` or `ZoneOffset` object.
) ;
Типы в MS SQL Server
Тип smalldatetime
в Microsoft SQL Server является нестандартным устаревшим типом.Документация рекомендует использовать другие типы в настоящее время.Обратите внимание, что будущие даты ограничены 6 июня 2079 года.
Этот тип представляет собой просто дату и время суток с разрешением в целые секунды.Так что этот тип не представляет момент.Без контекста часового пояса или смещения от UTC мы не можем определить момент.smalldatetime
представляет потенциальные моменты в диапазоне около 26-27 часов, диапазоне часовых поясов по всему земному шару.Так, например, 2019-01-23 12:00:00 может означать полдень в Токио, или полдень в Калькутте, или полдень в Париже, или полдень в Монреале - все это разные моменты на расстоянии нескольких часов друг от друга.
Типы в Java
Вы используете ужасные классы даты и времени (java.sql.Date
или java.util.Date
), которые сейчас унаследованы, вытеснены годами назад современным java.time классы, определенные в JSR 310.
Эквивалентный тип smalldatetime
в Java - LocalDateTime
, дата с указанием времени дня, но без часового пояса или смещения от UTC.
LocalDateTime ldt = LocalDateTime.of( 2018 , Month.MAY , 18 , 22 , 42 , 22 ) ;
В JDBC 4.2 и более поздних версиях мы можем напрямую обмениваться некоторыми типами java.time с базой данных.Я не использую Microsoft SQL Server, поэтому я не пробовал это.Но вы должны иметь возможность отправить LocalDateTime
Java-объект в столбец smalldatetime
.
Используйте подготовленный оператор с заполнителем ?
в вашем коде SQL.
myPreparedStatement.setObject( … , ldt ) ;
Извлечение.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;
Текущий момент
Дата сегодня = новая Дата ();
Сначала обратите внимание на разницу между java.util.Date
и java.sql.Date
.Первый представляет момент в UTC.Второе претендует на то, чтобы представлять только дату без времени суток и без зоны / смещения, но на самом деле имеет как время суток, так и зону / смещение, поскольку оно наследуется от другого Date
в ужасно плохом состоянии.взлом классного дизайна.Вам не следует использовать класс Date
.
Очевидно, вы пытаетесь представить текущий момент в столбце smalldatetime
. Это не имеет смысла. Как обсуждалось выше, вы не можете представить момент в smalldatetime
.Таким образом, вы неправильно смешиваете неправильные типы.
Если вы настаиваете на продолжении, я думаю, вы можете подделать это.
Давайте захватим текущий момент.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
JDBC 4.2 не требует поддержки Instant
.Итак, давайте преобразуем это в OffsetDateTime
объект, указывающий смещение от UTC, равное нулю часов-минут-секунд на момент в самом UTC.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
Ярлык: захват текущего момента как OffsetDateTime
.
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
Если бы вы правильно использовали столбец типа, похожего на стандарт SQL TIMESTAMP WITH TIME ZONE
, вы бы передали это OffsetDateTime
.
myPreparedStatement.setObject( … , odt ) ;
Но нам нужно удаляет информацию о смещении от UTC в качестве хака для размещения вашего столбца smalldatetime
.
LocalDateTime ldt = odt.toLocalDateTime() ; // Data loss: Discarding valuable information about offset-from-UTC.
Отправляет этот объект LocalDateTime
в базу данных, как указано выше.
myPreparedStatment.setObject( … , ldt ) ;
Ярлык, который я делаю Не Рекомендую: Звоните now
на LocalDateTime
.По моему мнению, включение метода LocalDateTime.now
в API java.time было ошибкой.Я не могу себе представить, когда это уместноВ этом случае это может сбить читателя с толку, поскольку мы не узнаем, понимаете ли вы проблемы, связанные с попыткой сохранить момент, но не включив информацию о зоне / смещении.
Но если вы настаиваете на моих советах:
myPreparedStatement.setObject (
… ,
LocalDateTime.now( ZoneOffset.UTC ) // Or some other `ZoneId` or `ZoneOffset` object.
) ;
О java.time
Платформа java.time встроена в Java8 и позже.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date
, Calendar
и & SimpleDateFormat
.
Чтобы узнать больше, см. Учебное пособие по Oracle .И поиск переполнения стека для многих примеров и объяснений.Спецификация: JSR 310 .
Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на java.time классы.
Вы можете обмениваться java.time объектами напрямую с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.*
классах.
Где получить классы java.time?
ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Вы можете найти здесь несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и more .