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
Modern java.time sınıfları tarafından değiştirilen, artık eski olan zahmetli eski tarih-saat sınıflarını kullanıyorsunuz .
Görünüşe göre veritabanınızda bir anı tam sayı türünde bir sütunda depoluyorsunuz. Bu talihsiz bir durum. Bunun yerine, SQL standardı gibi bir sütun türü kullanmalısınız TIMESTAMP WITH TIME ZONE
. Ama bu Cevap için elimizdekiyle çalışacağız.
Kayıtlarınız milisaniye çözünürlüklü anları temsil ediyorsa ve tüm kayıtları tüm gün için istiyorsanız, o zaman bir zaman aralığına ihtiyacımız var. Bir başlangıç anımız ve bir durma anımız olmalı. Sorgunuzda bir çifti olması gereken tek bir tarih-saat kriteri vardır.
LocalDate
Sınıf zaman günün-ve saat dilimi bulunmayan olmadan tarih salt değerini temsil eder.
Tarih belirlemede saat dilimi çok önemlidir. Herhangi bir an için tarih, dünya genelinde bölgeye göre değişir. Örneğin, Paris'te gece yarısından birkaç dakika sonra Fransa , Montréal Québec'te hala "dün" iken yeni bir gündür .
Saat dilimi belirtilmezse, JVM, geçerli varsayılan saat dilimini örtük olarak uygular. Bu varsayılan her an değişebilir, bu nedenle sonuçlarınız değişebilir. İstediğiniz / beklenen saat dilimini açıkça bir bağımsız değişken olarak belirtmek daha iyidir.
Bir belirtme uygun bir zaman dilimi adı biçiminde continent/region
gibi America/Montreal
, Africa/Casablanca
ya da Pacific/Auckland
. Hiçbir zaman gibi 3-4 harfli bir kısaltma kullanın EST
veya IST
oldukları gibi değil , gerçek zaman dilimleri, değil standardize ve hatta benzersiz değil (!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
JVM'nin mevcut varsayılan saat dilimini kullanmak istiyorsanız, bunu sorun ve bağımsız değişken olarak iletin. Atlanırsa, JVM'nin mevcut varsayılanı örtük olarak uygulanır. Açıkça belirtmek daha iyidir, çünkü varsayılan, çalışma süresi sırasında herhangi bir anda JVM içindeki herhangi bir uygulamanın herhangi bir iş parçacığındaki herhangi bir kodla değiştirilebilir .
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Veya bir tarih belirtin. Ayı, Ocak-Aralık için 1-12 arası mantıklı bir sayı ile ayarlayabilirsiniz.
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.
Veya daha iyisi, Month
yılın her ayı için önceden tanımlanmış enum nesnelerini kullanın . İpucu: Month
Kodunuzu daha fazla kendi kendini belgelendirmek, geçerli değerleri garantilemek ve tür güvenliği sağlamak için kod tabanınızda salt bir sayı yerine bu nesneleri kullanın .
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
Bir LocalDate
elimizdeyken, bunu bir çift ana, günün başlangıcı ve bitişi haline dönüştürmeliyiz. Günün 00: 00: 00'da başladığını varsaymayın. Yaz Saati Uygulaması (DST) gibi anormallikler nedeniyle gün 01:00:00 gibi başka bir saatte başlayabilir. Öyleyse java.time günün ilk anını belirlesin. Bu tür anormallikleri aramak için bir ZoneId
argüman LocalDate::atStartOfDay
iletiriz. Sonuç bir ZonedDateTime
.
ZonedDateTime zdtStart = ld.atStartOfDay( z ) ;
Genel olarak, bir zaman aralığını tanımlamaya yönelik en iyi yaklaşım, başlangıcın kapsayıcı , bitişin özel olduğu Yarı Açık yaklaşımdır . Yani bir gün ilk anıyla başlar ve ertesi günün ilk anına kadar devam eder, ancak buna dahil olmaz.
ZonedDateTime zdtStop = ld.plusDays( 1 ).atStartOfDay( z ) ; // Determine the following date, and ask for the first moment of that day.
Bütün gün sorgumuz SQL komutunu kullanamaz BETWEEN
. Bu komut Tam Kapalı ( []
) (hem başlangıç hem de son kapsayıcıdır) ve Yarı Açık ( [)
) istediğimiz yerde . Bir çift kriter kullanıyoruz >=
ve <
.
Sütununuzun adı kötü. Çeşitli veritabanları tarafından ayrılmış bin kelimeden herhangi birinden kaçının. placed
Bu örnekte kullanalım .
Kodunuz, ?
anlarımızı belirtmek için yer tutucular kullanmalıdır.
String sql = "SELECT * FROM orders WHERE placed >= ? AND placed < ? ; " ;
Ancak elimizde ZonedDateTime
nesneler var , veritabanınız görünüşe göre yukarıda tartışıldığı gibi tamsayılar saklıyor. Eğer varsa etmişti sütununuzu tanımlı düzgün biz sadece geçebileceği ZonedDateTime
sonra JDBC 4.2 veya destekleyen herhangi bir JDBC sürücüsü ile nesneleri.
Ancak bunun yerine, tam saniyeler içinde bir çağın sayımına ihtiyacımız var. Dönem referans tarihinizin UTC'deki 1970'in ilk anı olduğunu varsayacağım. ZonedDateTime
Sınıf nanosaniye çözünürlük yeteneğine sahip olduğundan , olası veri kaybına dikkat edin . Herhangi bir kesirli saniye aşağıdaki satırlarda kesilecektir.
long start = zdtStart().toEpochSecond() ; // Transform to a count of whole seconds since 1970-01-01T00:00:00Z.
long stop = zdtStop().toEpochSecond() ;
Artık bu tam sayıları yukarıda tanımlanan SQL kodumuza geçirmeye hazırız.
PreparedStatement ps = con.prepareStatement( sql );
ps.setObject( 1 , start ) ;
ps.setObject( 2 , stop ) ;
ResultSet rs = ps.executeQuery();
Tamsayı değerlerinizi öğesinden aldığınızda ResultSet
, Instant
nesnelere (her zaman UTC'de) veya ZonedDateTime
nesnelere (atanmış bir saat dilimiyle) dönüştürebilirsiniz.
Instant instant = rs.getObject( … , Instant.class ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Hakkında java.time
Java.time çerçevesi daha sonra Java 8 ve yerleşiktir. Bu sınıflar zahmetli eski yerini mirası gibi tarih-saat sınıfları java.util.Date
, Calendar
& SimpleDateFormat
.
Şu anda bakım modunda olan Joda-Time projesi, java.time sınıflarına geçişi önerir .
Daha fazla bilgi edinmek için Oracle Eğitimi'ne bakın . Ve birçok örnek ve açıklama için Stack Overflow'da arama yapın. Spesifikasyon JSR 310'dur .
Java.time sınıflarını nereden edinebilirim?
ThreeTen-Ekstra proje ek sınıfları ile java.time uzanır. Bu proje, java.time'a gelecekteki olası eklemeler için kanıtlayıcı bir zemindir. Burada bazı yararlı sınıfları gibi bulabilir Interval
, YearWeek
, YearQuarter
, ve daha .