java.util.Date
vs java.sql.Date
: ne zaman ve neden kullanılır?
java.util.Date
vs java.sql.Date
: ne zaman ve neden kullanılır?
Yanıtlar:
Tebrikler, JDBC: Date class taşıma ile en sevdiğim evcil hayvanımla karşılaştınız.
Temel olarak veritabanları genellikle tarih, saat ve zaman damgası olan en az üç datetime alanı biçimini destekler . Bunların her birijava.util.Date
JDBC'de karşılık gelen bir sınıfa sahiptir ve her biri genişler . Bu üçünün her birinin hızlı semantiği şöyledir:
java.sql.Date
saat, dakika, saniye ve milisaniye göz ardı edilirken yıl, ay ve gün depoladığı anlamına gelen SQL DATE değerine karşılık gelir . Ek olarak zaman dilimlerine bağlı değildir.sql.Date
java.sql.Time
SQL TIME değerine karşılık gelir ve açıkça görüleceği gibi yalnızca saat, dakika, saniye ve milisaniye hakkında bilgi içerir .java.sql.Timestamp
özelleştirilebilir hassasiyetle nanosaniyenin kesin tarihi olan SQL TIMESTAMP'e karşılık gelir ( yalnızca milisaniyeyi desteklediğine dikkat edin util.Date
! ).Bu üç türle ilgili olarak JDBC sürücülerini kullanırken en yaygın hatalardan biri, türlerin yanlış işlenmesidir. Bu sql.Date
, saat dilimine özgü olduğu anlamına gelir ,sql.Time
, cari yıl, ay ve günü ve cetera et cetera'yı içerdiği .
Gerçekten, alanın SQL türüne bağlıdır. PreparedStatement
Her üç değerler için ayarlayıcılar vardır #setDate()
için bir varlık sql.Date
, #setTime()
için sql.Time
ve #setTimestamp()
için sql.Timestamp
.
Kullanırsanız, çoğu doğru JDBC sürücüsüne ps.setObject(fieldIndex, utilDateObject);
normal bir util.Date
şekilde verebileceğinizi unutmayın, bu da doğru türdeymiş gibi mutlu bir şekilde yiyecektir, ancak daha sonra veri talep ettiğinizde, aslında bir şeyleri kaçırdığınızı fark edebilirsiniz.
Diyorum ki milisaniye / nanosaniye düz uzun olarak kaydetmek ve kullandığınız nesneleri ( zorunlu joda-zaman fişi ) ne onları dönüştürmek . Yapılabilecek bir hacky yolu tarih bileşenini bir uzun ve zaman bileşeni olarak diğeri olarak saklamaktır, örneğin şu anda 20100221 ve 154536123 olacaktır. Bu sihirli sayılar SQL sorgularında kullanılabilir ve veritabanından diğerine taşınabilir olacak ve JDBC / Java Tarih API'sının bu bölümünden tamamen kurtulmanızı sağlar.
GEÇ DÜZENLEME: Java 8 ile başlayarak ne kullanmamalı ne java.util.Date
de bundan kaçınamıyorsanız java.sql.Date
, bunun yerine java.time
başka bir şey yerine paketi (Joda'ya dayalı) kullanmayı tercih etmelisiniz . Java 8'de değilseniz, orijinal yanıt şudur:
java.sql.Date
- onu kullanan kütüphanelerin yöntemlerini / kurucularını çağırdığınızda (JDBC gibi). Başka türlü. JDBC ile açıkça ilgilenmeyen uygulamalar / modüller için veritabanı kitaplıklarına bağımlılık getirmek istemezsiniz.
java.util.Date
- onu kullanan kütüphaneleri kullanırken. Aksi takdirde, birkaç nedenden dolayı mümkün olduğunca az:
Değişebilir, yani her yönteme geçirdiğinizde veya bir yöntemden geri döndüğünüzde bunun bir savunma kopyasını almanız gerekir.
Sizinki gibi insanları gerçekten geriye doğru, tarih işleme sınıflarının yapması gerektiğini düşünen tarihleri çok iyi işlemez.
Şimdi, juD çok iyi iş yapmadığı için, korkunç Calendar
sınıflar tanıtıldı. Ayrıca değiştirilebilir ve çalışmak için korkunç ve herhangi bir seçeneğiniz yoksa kaçınılmalıdır.
Joda Time API gibi daha iyi alternatifler var ( Java 7'ye bile girebilir ve yeni resmi tarih işleme API'sı olabilir - hızlı bir arama yapmayacağını söylüyor).
Joda gibi yeni bir bağımlılık long
getirmenin aşırıya kaçtığını düşünüyorsanız, nesnelerdeki zaman damgası alanları için kullanmak o kadar da kötü değil, ancak kendimi genellikle onları geçerken, tür güvenliği ve dokümantasyon için juD'ye sarıyorum.
java.sql.Date
ile PreparedStatement
vs! Ancak etrafta geçerken, LocalDate
kullanarak java.sql.Date.valueOf
ve java.sql.Date.valueOf
ayarlarken dönüştürdüğünüz bir aracı kullanın ve mümkün olduğunca erken geri dönüştürün java.sql.Date.toLocalDate
- tekrar, çünkü java.sql'yi olabildiğince az dahil etmek ve değişebilir olduğu için.
Kullanılacak tek zaman java.sql.Date
a PreparedStatement.setDate
. Aksi takdirde kullanın java.util.Date
. Bunun ResultSet.getDate
bir a döndürdüğünü söylüyor java.sql.Date
ancak doğrudan a'ya atanabiliyor java.util.Date
.
java.sql.Date
atanabileceğini 'söylüyor' java.util.Date
? Ne yapmaya çalışıyorsun?
Aynı sorunu vardı, hazır bir ifadeye geçerli tarihi eklemek için bulduğum en kolay yolu bu:
preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
Hiçbirini kullanmayın.
java.time.Instant
cümledeki java.util.Date
java.time.LocalDate
cümledeki java.sql.Date
java.util.Date vs java.sql.Date: ne zaman ve neden kullanılır?
Bu sınıfların her ikisi de korkunç, tasarımda ve uygulamada kusurlu. Veba Coronavirüs gibi önlemek .
Bunun yerine JSR 310'da tanımlanan java.time sınıflarını kullanın. Bu sınıflar, tarih ve zaman işleme ile çalışmak için endüstri lideri bir çerçevedir. Bu yerini tamamen kanlı korkunç eski sınıfları gibi Date
, Calendar
, SimpleDateFormat
ve bu.
java.util.Date
Birincisi, java.util.Date
UTC'de bir anı temsil eder, yani UTC'den sıfır saat-dakika-saniye ofseti.
java.time.Instant
Şimdi ile değiştirildi java.time.Instant
.
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC.
java.time.OffsetDateTime
Instant
java.time öğesinin temel yapı taşı sınıfıdır . Daha fazla esneklik için aynı amaç için OffsetDateTime
set değerini kullanın ZoneOffset.UTC
: UTC'de bir anı temsil etme.
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
Sen kullanarak bir veritabanına bu nesneyi gönderebilirsiniz PreparedStatement::setObject
ile JDBC sonra 4.2 veya.
myPreparedStatement.setObject( … , odt ) ;
Al.
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
java.sql.Date
java.sql.Date
Sınıfı da korkunç ve kullanılmamaktadır.
Bu sınıf, günün saati ve saat dilimi olmadan yalnızca bir tarihi temsil eder. Ne yazık ki, bir tasarımın korkunç bir hackinde, bu sınıf java.util.Date
bir anı (UTC'de günün saati olan bir tarih) temsil eden miras alır . Yani bu sınıf sadece günün tarihi gibi davranıyor ve aynı zamanda UTC'nin günün saati ve üstü kapalı ofsetini taşıyor. Bu çok karışıklığa neden oluyor. Asla bu sınıfı kullanmayın.
java.time.LocalDate
Bunun yerine, java.time.LocalDate
günün herhangi bir saati veya herhangi bir saat dilimi veya ofset olmadan yalnızca bir tarihi (yıl, ay, ayın günü) izlemek için kullanın .
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate ld = LocalDate.now( z ) ; // Capture the current date as seen in the wall-clock time used by the people of a particular region (a time zone).
Veritabanına gönderin.
myPreparedStatement.setObject( … , ld ) ;
Al.
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
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
.
Daha fazla bilgi için Oracle Eğiticisine bakın . Ve birçok örnek ve açıklama için Stack Overflow'da arama yapın. Spesifikasyon JSR 310'dur .
Artık bakım modunda olan Joda-Time projesi java.time sınıflarına geçişi tavsiye ediyor .
Sen değiştirebilir java.time sizin veritabanı ile doğrudan nesneleri. JDBC 4.2 veya sonraki bir sürümüyle uyumlu bir JDBC sürücüsü kullanın . Dizeye gerek yok, gerek yokjava.sql.*
sınıflara .
Java.time sınıflarını nereden edinebilirsiniz?
Java'daki java.util.Date sınıfı belirli bir anı temsil eder (e, .g., 2013 Kasım 25 16:30:45 milisaniyeye kadar), ancak DB'deki DATE veri türü yalnızca bir tarihi temsil eder (ör. 25 Kasım 2013). Yanlışlıkla DB'ye bir java.util.Date nesnesi vermenizi önlemek için Java, java.util.Date'e doğrudan bir SQL parametresi ayarlamanıza izin vermez:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, d); //will not work
Ancak yine de bunu zorla / niyetle yapmanıza izin verir (o zaman saatler ve dakikalar DB sürücüsü tarafından göz ardı edilir). Bu, java.sql.Date sınıfı ile yapılır:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, new java.sql.Date(d.getTime())); //will work
Bir java.sql.Date nesnesi bir anı saklayabilir (böylece bir java.util.Date'den inşa etmek kolaydır), ancak saatlerce sormaya çalışırsanız (bir varlık kavramını zorlamak için) bir istisna atar. yalnızca tarih). DB sürücüsünün bu sınıfı tanıması ve saatlerce 0 kullanması beklenir. Bunu dene:
public static void main(String[] args) {
java.util.Date d1 = new java.util.Date(12345);//ms since 1970 Jan 1 midnight
java.sql.Date d2 = new java.sql.Date(12345);
System.out.println(d1.getHours());
System.out.println(d2.getHours());
}
java.util.Date
milisaniye hassasiyetinde belirli bir anı temsil eder. Saat dilimi olmadan hem tarih hem de saat bilgilerini temsil eder. Java.util.Date sınıfı Serializable, Cloneable ve Comparable arabirimini uygular. Bu tarafından devralınan java.sql.Date
, java.sql.Time
ve java.sql.Timestamp
arayüzler.
java.sql.Date
zaman bilgisi olmadan tarihi temsil eden java.util.Date sınıfını genişletir ve yalnızca veritabanlarıyla uğraşırken kullanılmalıdır. SQL DATE tanımına uymak için milisaniye değerleri birjava.sql.Date
örneğin örneğe , örneğin ilişkilendirildiği belirli saat diliminde saat, dakika, saniye ve milisaniye sıfıra ayarlanmasıyla 'normalleştirilmesi' gerekir.
Bu tüm genel yöntemleri devralır java.util.Date
gibi getHours()
, getMinutes()
, getSeconds()
, setHours()
, setMinutes()
, setSeconds()
. As java.sql.Date
ondan her zaman işlemlerini geçersiz, zaman bilgileri saklamaz java.util.Date
ve bu yöntemlerin hepsi atmak java.lang.IllegalArgumentException
bunların uygulanması ayrıntılarından belirgin olarak çağrıldığında.