tl; dr
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;
Instant instant = myResultSet.getObject( … , Instant.class ) ; // Retrieve a `TIMESTAMP WITH TIME ZONE` value in database as an `Instant` for a date with time-of-day in UTC with a resolution as fine as nanoseconds.
LocalDate ld = instant.atOffset( ZoneOffset.UTC ).toLocalDate() ; // Extract a date-only value without time-of-day and without time zone.
if ( ld.isBefore( today ) ) { … } // Compare `LocalDate` objects.
else if ( ld.isEqual( today ) ) { … }
else if ( ld.isAfter( today ) ) { … }
else { … handle error }
java.time
Вы используете и неправильно используете старые классы даты и времени.
Как отмечали другие:
- Стандартный
DATE
тип SQL содержит только дату без времени суток и без часового пояса - унаследованный класс
java.util.Date
назван неправильно и содержит дату и время суток в UTC . - Унаследованный класс
java.sql.Date
претендует на сохранение толькодата, но на самом деле имеет время суток, потому что этот класс наследует от вышеупомянутого, в то время как документация говорит нам игнорировать этот факт в нашем использовании.(Да, это сбивает с толку, и это плохой дизайн, неуклюжий взлом.)
Никогда не используйте java.util.Date
, java.util.Calendar
, java.sql.Timestamp
, java.sql.Date
и связанные с ними классы.Вместо этого используйте только вменяемые java.time классы.Они лидируют в отрасли в области чистого дизайна и глубины понимания работы с датой и временем, почерпнутого из опыта их предшественника, проекта Joda-Time .
Длязначение только для даты, хранящееся в стандартном для SQL типе базы данных DATE
, используйте java.time.LocalDate
.
LocalDate ld = myResultSet.get( … , LocalDate.class ) ; // Retrieving from database.
myPreparedStatement.setObject( … , ld ) ; // Storing in database.
Для даты с временем суток в значении UTC,хранится в базе данных стандарта SQL типа TIMESTAMP WITH TIME ZONE
, используйте java.time.Instant
.Класс Instant
представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).
Instant instant = myResultSet.get( … , Instant.class ) ; // Retrieving from database.
myPreparedStatement.setObject( … , instant ) ; // Storing in database.
Для сравнения в Java используйте методы isEqual
, isBefore
, isAfter
, equals
или compare
.
Boolean overdue = someLocalDate.isAfter( otherLocalDate ) ;
Часовой пояс
Часовой пояс имеет решающее значение при определении даты и времени суток с момента (Instant
/ TIMESTAMP WITH TIME ZONE
).
После получения значения TIMESTAMP WITH TIME ZONE
из базы данных в виде Instant
, настройте в часовой пояс или смещение-от-UTC , время настенных часовВы хотите использовать в восприятии даты и времени суток.Для часового пояса примените ZoneId
, чтобы получить ZonedDateTime
объект.Для смещения от UTC примените ZoneOffset
, чтобы получить OffsetDateTime
объект.В любом случае извлеките значение только для даты, вызвав toLocalDate
, чтобы получить объект LocalDate
.
В вашем случае вы, очевидно, хотите воспринимать дату как UTC.Поэтому примените константу ZoneOffset.UTC
, чтобы получить OffsetDateTime
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
LocalDate ld = odt.toLocalDate() ; // Extract a date-only value without time-of-day and without time zone.
Мы хотим сравнить с текущей датой в UTC.
LocalDate today = LocalDate.now( ZoneOffset.UTC ) ; // Specify the offset/zone by which you want to perceive the current date.
Сравнить.
if ( ld.isBefore( today ) ) { … }
else if ( ld.isEqual( today ) ) { … }
else if ( ld.isAfter( today ) ) { … }
else { … handle error }
ISO 8601
Избегайте ненужного использования пользовательских форматов, таких как "гггг / мм / дд".По возможности используйте стандартные форматы ISO 8601 .
Для значения только для даты это будет ГГГГ-ММ-ДД.
String output = LocalDate.now().toString() ; // Ex: 2018-01-23
Пример с H2
Вот полный пример написания, запроса и чтения LocalDate
объектов из столбца базы данных стандарта SQL DATE
тип.
Использование H2 Database Engine , так как я не MySQL пользователь.Создание базы данных в памяти, а не запись в хранилище.Я предполагаю, что код будет почти таким же для MySQL.
try (
Connection conn = DriverManager.getConnection( "jdbc:h2:mem:trashme" )
) {
String sql = "CREATE TABLE " + "tbl_" + " (\n" +
" uuid_ UUID DEFAULT random_uuid() , \n" + // Every table should have a primary key.
" when_ DATE \n" + // Three columns per the Question.
" );";
try (
Statement stmt = conn.createStatement() ;
) {
stmt.execute( sql );
}
sql = "INSERT INTO tbl_ ( when_ ) VALUES ( ? ) ;";
LocalDate start = LocalDate.of( 2018 , Month.JANUARY , 23 );
LocalDate ld = start; // Keep the `start` object for use later.
try (
PreparedStatement ps = conn.prepareStatement( sql )
) {
for ( int i = 1 ; i <= 10 ; i++ ) {
ps.setObject( 1 , ld );
ps.executeUpdate();
// Prepare for next loop.
int randomNumber = ThreadLocalRandom.current().nextInt( 1 , 5 + 1 ); // Pass minimum & ( maximum + 1 ).
ld = ld.plusDays( randomNumber ); // Add a few days, an arbitrary number.
}
}
// Dump all rows, to verify our populating of table.
System.out.println( "Dumping all rows: uuid_ & when_ columns." );
sql = "SELECT uuid_ , when_ FROM tbl_ ; ";
int rowCount = 0;
try (
Statement stmt = conn.createStatement() ;
ResultSet rs = stmt.executeQuery( sql ) ;
) {
while ( rs.next() ) {
rowCount++;
UUID uuid = rs.getObject( 1 , UUID.class );
LocalDate localDate = rs.getObject( 2 , LocalDate.class );
System.out.println( uuid + " " + localDate );
}
}
System.out.println( "Done dumping " + rowCount + " rows." );
// Dump all rows, to verify our populating of table.
System.out.println( "Dumping rows where `when_` is after " + start + ": uuid_ & when_ columns." );
sql = "SELECT uuid_ , when_ FROM tbl_ WHERE when_ > ? ; ";
rowCount = 0; // Reset count.
final PreparedStatement ps = conn.prepareStatement( sql );
ps.setObject( 1 , start );
try (
ps ;
ResultSet rs = ps.executeQuery() ;
) {
while ( rs.next() ) {
rowCount++;
UUID uuid = rs.getObject( 1 , UUID.class );
LocalDate localDate = rs.getObject( 2 , LocalDate.class );
System.out.println( uuid + " " + localDate );
}
}
System.out.println( "Done dumping " + rowCount + " rows." );
} catch ( SQLException eArg ) {
eArg.printStackTrace();
}
При запуске.
Dumping all rows: uuid_ & when_ columns.
e9c75998-cd67-4ef9-9dce-6c1eed170387 2018-01-23
741c1452-e224-4e5e-95bc-904d8db58b39 2018-01-27
413de43c-a1be-40b6-9ccf-a9b7d9ba873c 2018-01-31
e2aa148f-48b6-4be6-a0fe-f2881b6b5a63 2018-02-03
f498003c-2d8b-446e-ac55-6d7568ce61c3 2018-02-06
c41606d7-8c05-4bba-9f8e-2a0d1f1bb31a 2018-02-09
3df3abe3-1865-4632-99c4-6cd74883c1ee 2018-02-10
914153fe-34f2-4e4f-a91b-944314994839 2018-02-13
96436bdf-80ee-4afe-b55d-f240140ace6a 2018-02-16
82b43f7b-077d-45c1-8c4f-f5b30dfdd44a 2018-02-19
Done dumping 10 rows.
Dumping rows where `when_` is after 2018-01-23: uuid_ & when_ columns.
741c1452-e224-4e5e-95bc-904d8db58b39 2018-01-27
413de43c-a1be-40b6-9ccf-a9b7d9ba873c 2018-01-31
e2aa148f-48b6-4be6-a0fe-f2881b6b5a63 2018-02-03
f498003c-2d8b-446e-ac55-6d7568ce61c3 2018-02-06
c41606d7-8c05-4bba-9f8e-2a0d1f1bb31a 2018-02-09
3df3abe3-1865-4632-99c4-6cd74883c1ee 2018-02-10
914153fe-34f2-4e4f-a91b-944314994839 2018-02-13
96436bdf-80ee-4afe-b55d-f240140ace6a 2018-02-16
82b43f7b-077d-45c1-8c4f-f5b30dfdd44a 2018-02-19
Done dumping 9 rows.
О java.time
java.time Framework встроен в 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 .