tl; др
- Никогда не используйте
java.sql.Date
или java.util.Date
.Используйте только java.time классы. - Для значения только на дату используйте
LocalDate
.Вы увидите только стабильные значения без влияния перехода на летнее время (DST).
Пример:
LocalDate.parse( "2019-01-23" )
java.sql.Date
означает , а не дату
Я не совсем уверен, в чем проблема, но я подозреваю, что это связано с использованием вами ужасного класса java.sql.Date
, и, следовательно, спорным.
java.sql.Date
class делает вид, что представляет значение только для даты, без времени суток и без часового пояса.Однако из-за некоторых невообразимо плохих дизайнерских решений этот класс расширяется java.util.Date
.java.util.Date
класс имеет время суток и находится в UTC.Еще более запутанно то, что java.util.Date
имеет часовой пояс, скрытый в исходном коде без методов получения и установки, поэтому, похоже, его еще нет, что влияет на поведение таких методов, как equals
.Таким образом, java.sql.Date
, несмотря на название и цель хранения только даты, на самом деле имеет время суток, установленное в UTC.Так что java.sql.Date
делает несколько трюков в настройке времени суток, что, вероятно, является проблемой, с которой вы сталкиваетесь.Эти устаревшие классы даты и времени представляют собой большую дымящуюся кучу… овсянки.Никогда не используйте их.
Чтобы процитировать JavaDoc для класса java.sql.Date
:
Тонкая оболочка вокруг миллисекундного значения, позволяющая JDBC идентифицироватьэто как значение SQL DATE.Значение в миллисекундах представляет количество миллисекунд, прошедших с 1 января 1970 года 00: 00: 00.000 GMT.
Чтобы соответствовать определению SQL DATE, значения в миллисекундах переносятся экземпляром java.sql.Date.должно быть «нормализовано» путем установки часов, минут, секунд и миллисекунд на ноль в конкретном часовом поясе, с которым связан экземпляр.
Кстати, java.sql.Timestamp
такой же плохой беспорядок.Он также неуклюже наследует от java.util.Date
, добавляя секунду доли секунды для наносекунд.Также избегайте этого класса, теперь его заменяют на java.time.Instant
или java.time.OffsetDateTime
.Аналогично, java.sql.Time
заменяется на java.time.LocalTime
.
java.time.LocalDate
- это по-настоящему дата
С внедрением JSR 310 и JDBC 4.2 вы можете использовать современные ведущие java.time классы.К настоящему времени Джексон, возможно, был обновлен для использования java.time .Если нет, см. этот вопрос для ссылок на модули типа данных для обработки java.time в Джексоне.
Похоже, что ваши входные строки в стандарте Формат ISO 8601 , ГГГГ-ММ-ДД.Классы java.time по умолчанию используют стандартные форматы при разборе / генерации строк, представляющих значения даты и времени.Для использования только по дате LocalDate
класс, который действительно является датой без времени суток и без зоны / смещения.Вы увидите стабильные значения даты без изменений: Летнее время (DST) .
Разбор.
LocalDate ld = LocalDate.parse( "2019-01-23" ) ;
Store.
myPreparedStatement.setObject( … , ld ) ;
Получить.
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
О LocalDate
Класс LocalDate
представляет значение только для даты без времени суток и без часовой пояс или смещение от UTC .
Часовой пояс имеет решающее значение при определении даты.В любой момент времени дата меняется по всему земному шару в зависимости от зоны.Например, через несколько минут после полуночи в Париж Франция - это новый день, в то время как «вчера» в Монреаль Квебек .
Если часовой пояс не указан,JVM неявно применяет свой текущий часовой пояс по умолчанию.Это значение по умолчанию может измениться в любой момент во время выполнения (!), Поэтому ваши результаты могут отличаться.Лучше явно указать желаемый / ожидаемый часовой пояс в качестве аргумента.Если критично, подтвердите зону с вашим пользователем.
Spвведите правильное имя часового пояса в формате Continent/Region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
.Никогда не используйте 2-4-буквенное сокращение, такое как EST
или IST
, поскольку они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Если вы хотите использовать текущий часовой пояс JVM по умолчанию, запросите его и передайте в качестве аргумента.Если опущен, код становится неоднозначным для чтения, поскольку мы точно не знаем, намеревались ли вы использовать значение по умолчанию или если вы, как и многие другие программисты, не знали о проблеме.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Или укажитесвидание.Вы можете установить месяц по номеру, с нормальным номером 1-12 для января-декабря.
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
Или, лучше, использовать предварительно определенные объекты перечисления Month
, по одному на каждый месяц года.Совет: используйте эти Month
объекты по всей вашей кодовой базе, а не просто целое число, чтобы сделать ваш код более самодокументируемым, обеспечить допустимые значения и обеспечить type-safety .То же самое для Year
& YearMonth
.
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
О java.time
Инфраструктура java.time встроена в Java 8 и более поздние версии.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date
, Calendar
и & SimpleDateFormat
.
Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация: 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 .