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
, и более .