ТЛ; др
Используйте современные java.time классы, никогда java.util.Date
или java.sql.Date
или java.sql.Timestamp
.
myPreparedStatement // With JDBC 4.2, wa can directly exchange java.time objects with the database.
.setObject( // Pass a `OffsetDateTime` object representing the moment we want stored in the database.
LocalDateTime.parse( // Parse the input string lacking an indicator of offset or zone.
"2019-01-19T19:00" // When using strings in standard ISO 8601 format, no need to specify a formatting pattern.
) // Returns a `LocalDateTime`, an ambiguous value without real meaning.
.atZone( // Apply a time zone to give meaning to the `LocalDateTime`.
ZoneId.of( "Europe/Paris" ) // Here we are saying "the 7 PM on that date as seen on the clock on the wall of someone standing in Paris France".
) // Returns a `ZonedDateTime` object.
.toOffsetDateTime() // Returns an `OffsetDateTime` object as demanded by the JDBC spec, stripping off the time zone to leave on the hours-minutes-seconds from UTC.
)
java.time
Вы используете ужасные классы даты и времени, которые были вытеснены несколько лет назад классами java.time . На самом деле нет смысла пытаться отлаживать / понимать унаследованные классы, так как они чертовски ужасны.
LocalDateTime
Разберите вашу входную строку как LocalDateTime
, так как в ней отсутствует индикатор часовой пояс или смещение от UTC .
По возможности используйте стандартные форматы ISO 8601 для текста даты и времени. Для даты с временем суток будет YYYY-MM-DDTHH: MM: SS, где T
отделяет часть даты от части времени.
String input = "2019-01-19T19:00" ;
LocalDateTime ldt = LocalDateTime.parse( input ) ; // No need to specify formatting pattern when using standard ISO 8601 formats.
ZonedDateTime
В классе LocalDateTime
также отсутствует понятие зоны или смещения. Таким образом, объект этого класса не представляет момент, является не точкой на временной шкале. Он представляет потенциальные моменты в диапазоне около 26-27 часов, различные часовые пояса по всему земному шару.
Кажется, вы наверняка знаете, что эта дата и время должны были представлять момент в определенном часовом поясе. Поэтому примените часовой пояс, чтобы придать смысл нашему неоднозначному LocalDateTime
объекту.
Укажите собственное имя часового пояса в формате Continent/Region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
. Никогда не используйте 2-4 буквенные сокращения, такие как EST
или IST
, так как они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "Europe/Paris" ) ;
Если вы хотите использовать текущий часовой пояс JVM по умолчанию, запросите его и передайте в качестве аргумента. Если опущен, код становится неоднозначным для чтения, поскольку мы точно не знаем, намеревались ли вы использовать значение по умолчанию или если вы, как и многие программисты, не знали об этой проблеме.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Теперь мы можем применить ZoneId
, чтобы получить ZonedDateTime
.
ZonedDateTime zdt = ldt.atZone( z ) ;
OffsetDateTime
Ваш JDBC может принять объект ZonedDateTime
, но спецификация JDBC 4.2 требует, чтобы он принимал OffsetDateTime
. Какая разница? И ZonedDateTime
, и OffsetDateTime
представляют момент, точку на временной шкале. Смещение всего на несколько часов-минут-секунд вперед или назад по UTC. Часовой пояс гораздо больше. Часовой пояс - это история прошлых, настоящих и будущих изменений в смещении, используемом людьми определенного региона. Так что часовой пояс всегда предпочтительнее. За исключением случаев, когда мы используем JDBC для обмена объектом java.time с базой данных, мы используем OffsetDateTime
для написания стандартного кода.
OffsetDateTime odt = zdt.toOffsetDateTime() ; // Convert from moment with time zone to a moment with merely an offset-from-UTC.
Теперь мы можем передать этот момент вашему подготовленному заявлению.
myPreparedStatement( … , odt ) ; // Pass a `OffsetDateTime` moment as the value for a placeholder in the SQL of your prepared statement.
индексирование.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Назначьте нужный часовой пояс.
ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = odt.atZone( z ) ;
И odt
, и zdt
, показанные в нескольких приведенных выше строках, представляют один и тот же момент одновременности, одну и ту же точку на временной шкале. Отличается только их время на настенных часах, так как большинство баз данных хранят и извлекают UTC, пока вы хотите видеть время по Парижу.
О java.time
Платформа java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date
, Calendar
, & SimpleDateFormat
.
Проект Joda-Time , теперь в режиме обслуживания , рекомендует выполнить переход на классы java.time .
Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .
Вы можете обмениваться java.time объектами напрямую с вашей базой данных. Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.*
классах.
Где получить классы java.time?
ThreeTen-Extra Проект расширяет java.time дополнительными классами.Этот проект является полигоном для возможных будущих дополнений к java.time.Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и more .