tl; dr
LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
.atStartOfDay( ZoneId.of( "Africa/Tunis" ) )
.toEpochSecond()
…
LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
.plusDays( 1 )
.atStartOfDay( ZoneId.of( "Africa/Tunis" ) )
.toEpochSecond()
…
"SELECT * FROM orders WHERE placed >= ? AND placed < ? ; "
…
myPreparedStatement.setObject( 1 , start )
myPreparedStatement.setObject( 2 , stop )
java.time
Вы используете проблемные старые классы даты и времени, которые теперь являются устаревшими, вытесненными современными классами java.time .
По-видимому, вы сохраняете момент в своей базе данных в столбце какого-то целочисленного типа. Это прискорбно. Вместо этого вы должны использовать столбец такого типа, как стандарт SQL TIMESTAMP WITH TIME ZONE. Но для этого ответа мы будем работать с тем, что у нас есть.
Если ваши записи представляют моменты с разрешением в миллисекунды, и вам нужны все записи за целый день, тогда нам нужен временной диапазон. У нас должен быть момент начала и момент остановки. В вашем запросе есть только один критерий даты и времени, а у него должна быть пара.
LocalDateКласс представляет собой дату только значение без времени суток и без временной зоны.
Часовой пояс имеет решающее значение при определении даты. В любой момент дата меняется в зависимости от зоны земного шара. Например, несколько минут после полуночи в Париже, Франция - это новый день, в то время как в Монреаль-Квебеке все еще «вчера» .
Если часовой пояс не указан, JVM неявно применяет текущий часовой пояс по умолчанию. Это значение по умолчанию может измениться в любой момент, поэтому ваши результаты могут отличаться. Лучше явно указать желаемый / ожидаемый часовой пояс в качестве аргумента.
Укажите правильное время имя зоны в формате continent/region, например America/Montreal, Africa/Casablancaили Pacific/Auckland. Никогда не используйте аббревиатуру из 3–4 букв, например ESTили, ISTпоскольку они не являются истинными часовыми поясами, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Если вы хотите использовать текущий часовой пояс JVM по умолчанию, запросите его и передайте в качестве аргумента. Если опущено, текущее значение по умолчанию JVM применяется неявно. Лучше быть явным, поскольку значение по умолчанию может быть изменено в любой момент во время выполнения любым кодом в любом потоке любого приложения в 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объекты во всей кодовой базе, а не просто целое число, чтобы сделать ваш код более самодокументированным, гарантировать допустимые значения и обеспечить безопасность типов .
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Теперь LocalDateнам нужно преобразовать его в пару моментов: начало и конец дня. Не предполагайте, что день начинается в 00:00:00 по времени суток. Из-за аномалий, таких как переход на летнее время (DST), день может начинаться в другое время, например 01:00:00. Так что пусть java.time определяет первый момент дня. Мы передаем ZoneIdаргумент, чтобы LocalDate::atStartOfDayнайти любые такие аномалии. В результате получился файл ZonedDateTime.
ZonedDateTime zdtStart = ld.atStartOfDay( z ) ;
Как правило, лучший подход к определению промежутка времени - это полуоткрытый подход, когда начало включено, а окончание - исключено . Итак, день начинается с его первого момента и продолжается до первого момента следующего дня, но не включая его.
ZonedDateTime zdtStop = ld.plusDays( 1 ).atStartOfDay( z ) ; // Determine the following date, and ask for the first moment of that day.
Наш запрос на целый день не может использовать команду SQL BETWEEN. Эта команда - Fully-Closed ( []) (включая начало и конец), где, как мы хотим, Half-Open ( [)). Мы используем пару критериев >=и <.
Ваша колонка плохо названа. Избегайте любого из тысячи слов, зарезервированных в различных базах данных. Давайте использовать placedв этом примере.
В вашем коде должны быть ?заполнители для указания наших моментов.
String sql = "SELECT * FROM orders WHERE placed >= ? AND placed < ? ; " ;
Но у нас есть ZonedDateTimeобъекты, а ваша база данных, по-видимому, хранит целые числа, как обсуждалось выше. Если вы уже определили свой столбец правильно , мы могли бы просто передать ZonedDateTimeобъекты с любым драйвером JDBC с поддержкой JDBC 4.2 или более поздней версией.
Но вместо этого нам нужно получить отсчет от эпохи в целых секундах. Я предполагаю, что ваша контрольная дата эпохи - это первый момент 1970 года по всемирному координированному времени. Остерегайтесь возможной потери данных, так как этот ZonedDateTimeкласс имеет наносекундное разрешение. Любая дробная секунда будет усечена в следующих строках.
long start = zdtStart().toEpochSecond() ; // Transform to a count of whole seconds since 1970-01-01T00:00:00Z.
long stop = zdtStop().toEpochSecond() ;
Теперь мы готовы передать эти целые числа в наш код SQL, определенный выше.
PreparedStatement ps = con.prepareStatement( sql );
ps.setObject( 1 , start ) ;
ps.setObject( 2 , stop ) ;
ResultSet rs = ps.executeQuery();
Когда вы извлекаете свои целочисленные значения из ResultSet, вы можете преобразовывать их в Instantобъекты (всегда в формате UTC) или в ZonedDateTimeобъекты (с назначенным часовым поясом).
Instant instant = rs.getObject( … , Instant.class ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
О java.time
Java.time каркас встроен в Java 8 и более поздних версий. Эти классы вытеснять неприятные старые устаревшие классы даты и времени , такие как java.util.Date, Calendar, и SimpleDateFormat.
Проект Joda-Time , находящийся сейчас в режиме обслуживания , рекомендует перейти на классы java.time .
Чтобы узнать больше, см. Oracle Tutorial . И поищите в Stack Overflow множество примеров и объяснений. Спецификация - JSR 310 .
Где взять классы java.time?
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательной площадкой для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как Interval, YearWeek, YearQuarter, и более .