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
Anda menggunakan kelas tanggal-waktu lama yang merepotkan yang sekarang sudah lama, digantikan oleh kelas java.time modern .
Rupanya Anda menyimpan momen di database Anda dalam kolom jenis integer. Itu sangat disayangkan. Sebagai gantinya, Anda harus menggunakan kolom dengan tipe seperti standar SQL TIMESTAMP WITH TIME ZONE
. Tetapi, untuk Jawaban ini, kami akan bekerja dengan apa yang kami miliki.
Jika catatan Anda mewakili momen dengan resolusi milidetik, dan Anda menginginkan semua catatan untuk satu hari penuh, maka kami memerlukan rentang waktu. Kita harus memiliki momen awal dan momen berhenti. Kueri Anda hanya memiliki satu kriteria tanggal-waktu yang seharusnya memiliki pasangan.
The LocalDate
kelas mewakili nilai tanggal-hanya tanpa waktu-of-hari dan tanpa zona waktu.
Zona waktu sangat penting dalam menentukan tanggal. Untuk saat tertentu, tanggal bervariasi di seluruh dunia menurut zona. Misalnya, beberapa menit setelah tengah malam di Paris Prancis adalah hari baru sementara masih "kemarin" di Montréal Québec .
Jika tidak ada zona waktu yang ditentukan, JVM secara implisit menerapkan zona waktu default saat ini. Default itu dapat berubah setiap saat, jadi hasil Anda mungkin berbeda. Lebih baik menentukan zona waktu yang Anda inginkan / diharapkan secara eksplisit sebagai argumen.
Tentukan nama zona waktu yang tepat dalam format continent/region
, seperti America/Montreal
, Africa/Casablanca
, atau Pacific/Auckland
. Jangan pernah menggunakan singkatan 3-4 huruf seperti EST
atau IST
karena itu bukan zona waktu yang sebenarnya, tidak standar, dan bahkan tidak unik (!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
Jika Anda ingin menggunakan zona waktu default JVM saat ini, tanyakan dan berikan sebagai argumen. Jika dihilangkan, default JVM saat ini diterapkan secara implisit. Lebih baik eksplisit, karena default dapat diubah kapan saja selama runtime oleh kode apa pun di thread mana pun dari aplikasi apa pun dalam JVM.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Atau tentukan tanggal. Anda dapat mengatur bulan dengan angka, dengan penomoran 1-12 untuk Januari-Desember.
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.
Atau, lebih baik, gunakan Month
objek enum yang telah ditentukan sebelumnya, satu untuk setiap bulan dalam setahun. Tip: Gunakan Month
objek ini di seluruh basis kode Anda, bukan hanya bilangan bulat untuk membuat kode Anda lebih terdokumentasi sendiri, memastikan nilai yang valid, dan memberikan keamanan jenis .
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Dengan LocalDate
tangan, selanjutnya kita perlu mengubahnya menjadi momen, awal dan akhir hari. Jangan berasumsi bahwa hari dimulai pada pukul 00:00:00 waktu hari. Karena anomali seperti Daylight Saving Time (DST), hari tersebut dapat dimulai pada waktu lain seperti 01:00:00. Jadi biarkan java.time menentukan momen pertama hari itu. Kami memberikan ZoneId
argumen LocalDate::atStartOfDay
untuk mencari anomali semacam itu. Hasilnya adalah a ZonedDateTime
.
ZonedDateTime zdtStart = ld.atStartOfDay( z ) ;
Umumnya pendekatan terbaik untuk menentukan rentang waktu adalah pendekatan Setengah-Terbuka di mana permulaannya inklusif sedangkan akhir bersifat eksklusif . Jadi suatu hari dimulai dengan momen pertamanya dan berjalan hingga, tetapi tidak termasuk, momen pertama di hari berikutnya.
ZonedDateTime zdtStop = ld.plusDays( 1 ).atStartOfDay( z ) ; // Determine the following date, and ask for the first moment of that day.
Kueri kami sepanjang hari tidak dapat menggunakan perintah SQL BETWEEN
. Perintah itu Sepenuhnya-Tertutup ( []
) (baik awal dan akhir inklusif) di mana seperti yang kita inginkan Setengah-Terbuka ( [)
). Kami menggunakan sepasang kriteria >=
dan <
.
Kolom Anda dinamai dengan buruk. Hindari salah satu dari seribu kata yang dicadangkan oleh berbagai database. Mari kita gunakan placed
dalam contoh ini.
Kode Anda harus menggunakan ?
placeholder untuk menentukan momen kita.
String sql = "SELECT * FROM orders WHERE placed >= ? AND placed < ? ; " ;
Tapi kami memiliki ZonedDateTime
objek di tangan, sementara database Anda tampaknya menyimpan bilangan bulat seperti yang dibahas di atas. Jika Anda telah mendefinisikan kolom Anda dengan benar, kami dapat meneruskan ZonedDateTime
objek dengan driver JDBC yang mendukung JDBC 4.2 atau yang lebih baru.
Tapi sebaliknya kita perlu menghitung waktu dari waktu ke waktu dalam hitungan detik. Saya akan menganggap tanggal referensi zaman Anda adalah saat pertama tahun 1970 di UTC. Waspadai kemungkinan kehilangan data, karena ZonedDateTime
kelas tersebut mampu menghasilkan resolusi nanodetik. Detik pecahan apa pun akan dipotong di baris berikut.
long start = zdtStart().toEpochSecond() ; // Transform to a count of whole seconds since 1970-01-01T00:00:00Z.
long stop = zdtStop().toEpochSecond() ;
Sekarang kami siap untuk meneruskan bilangan bulat tersebut ke kode SQL kami yang ditentukan di atas.
PreparedStatement ps = con.prepareStatement( sql );
ps.setObject( 1 , start ) ;
ps.setObject( 2 , stop ) ;
ResultSet rs = ps.executeQuery();
Saat Anda mengambil nilai integer Anda dari ResultSet
, Anda dapat mengubahnya menjadi Instant
objek (selalu dalam UTC), atau menjadi ZonedDateTime
objek (dengan zona waktu yang ditetapkan).
Instant instant = rs.getObject( … , Instant.class ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Tentang java.time
The java.time kerangka dibangun ke Jawa 8 dan kemudian. Kelas-kelas ini menggantikan tua merepotkan warisan kelas tanggal-waktu seperti java.util.Date
, Calendar
, & SimpleDateFormat
.
Proyek Joda-Time , sekarang dalam mode pemeliharaan , menyarankan migrasi ke kelas java.time .
Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasinya adalah JSR 310 .
Dimana mendapatkan kelas java.time?
Proyek ThreeTen-Extra memperluas java.time dengan kelas tambahan. Proyek ini adalah tempat pembuktian untuk kemungkinan penambahan java.time di masa mendatang. Anda mungkin menemukan beberapa kelas berguna di sini seperti Interval
, YearWeek
, YearQuarter
, dan lebih .