java.util.Date vs java.sql.Date


Yanıtlar:


585

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.Datesaat, 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.TimeSQL 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 .

Sonunda: Hangisini kullanmalı?

Gerçekten, alanın SQL türüne bağlıdır. PreparedStatementHer üç değerler için ayarlayıcılar vardır #setDate()için bir varlık sql.Date, #setTime()için sql.Timeve #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.

Gerçekten hiçbir Tarihin hiç kullanılmaması gerektiğini söylüyorum.

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.


17
Güzel cevap. Ancak tarihleri ​​DBA için biraz düşmanca saklamak değil mi?
cherouvim

26
Bununla birlikte, DBA: lar genellikle RDBMS'lerine tercih etme eğilimindedir ve Java uygulamalarının hepsiyle çalışması beklenirken doğrudan RDBMS ile ilgili olmayan her şeyi ( size bakıyorum, Oracle hayranları ) reddeder . Şahsen mantığımı DB'ye koymak istemiyorum.
Esko

2
Benim mysql sütunu bir datetime, ancak ps.setDate (new java.sql.Date (myObject.getCreatedDate (). GetTime ())) yapıyor; Milisaniye bölümünü kaybediyorum, bu nasıl düzeltilir?
Blankman

2
Milisaniyenizi kaybetmemek için: new java.sql.Timestamp (utilDate.getTime ())
Kieveli

3
Ben şartname tarafından olmamalı iken bu TZ özgü yaygın bir hata olduğunu belirtti.
Esko

60

GEÇ DÜZENLEME: Java 8 ile başlayarak ne kullanmamalı ne java.util.Datede bundan kaçınamıyorsanız java.sql.Date, bunun yerine java.timebaş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 longgetirmenin 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.


5
Neden veritabanında saklarken java.time yerine java.sql tercih etmeliyiz? Açıklamada gerçekten ilginçim, ama nedenini anlamak istiyorum :)
Jean-François Savard

Jean-FrançoisSavard @ Ben size o görüş gönderdi beri Sorunuza bir cevap bulduk umut - ama burada sadece hatırı şeyiyle, bir cevap var: Hala hiçbir sakınca java.sql.Date ile PreparedStatementvs! Ancak etrafta geçerken, LocalDatekullanarak java.sql.Date.valueOfve java.sql.Date.valueOfayarlarken 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.
gustafc

19

Kullanılacak tek zaman java.sql.Datea PreparedStatement.setDate. Aksi takdirde kullanın java.util.Date. Bunun ResultSet.getDatebir a döndürdüğünü söylüyor java.sql.Dateancak doğrudan a'ya atanabiliyor java.util.Date.


3
Ehm, ResultSet # getDate () sql.Date değerini döndürür (util.Date öğesini genişletir).
Esko

3
@Esko - "Ehm", yorum yapmadan (ve indirilmeden) önce düzelttim.
Paul Tomblin

1
Bir java.sql.Date öğesinin java.util.Date öğesine atanabilmesinin neden birincisinin ikincinin bir alt sınıfı olması gerektiğine dikkat etmek önemlidir.
dj18

2
Neden birincinin ikincisini uzattığında a'nın java.sql.Dateatanabileceğini 'söylüyor' java.util.Date? Ne yapmaya çalışıyorsun?
Lorne Marquis

11

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()));

2
bununla saat dilimi alamıyorum.
erhanasikoglu

4

tl; Dr.

Hiçbirini kullanmayın.

ne

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, SimpleDateFormatve bu.

java.util.Date

Birincisi, java.util.DateUTC'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

Instantjava.time öğesinin temel yapı taşı sınıfıdır . Daha fazla esneklik için aynı amaç için OffsetDateTimeset 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::setObjectile JDBC sonra 4.2 veya.

myPreparedStatement.setObject(  , odt ) ;

Al.

OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;

java.sql.Date

java.sql.DateSı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.Datebir 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.LocalDategü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'da (hem eski hem de modern) ve standart SQL'de tarih-saat türleri tablosu


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.

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?

Hangi Java veya Android sürümüyle kullanılacak java.time kütüphanesinin tablosu


1
Plague referansını Corona virüsü ile değiştirmek için oy verin. Şimdi daha akraba.
ankuranurag2

2

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());
}

0

java.util.Datemilisaniye 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.Timeve java.sql.Timestamparayüzler.

java.sql.Datezaman 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.Dategibi getHours(), getMinutes(), getSeconds(), setHours(), setMinutes(), setSeconds(). As java.sql.Dateondan her zaman işlemlerini geçersiz, zaman bilgileri saklamaz java.util.Dateve bu yöntemlerin hepsi atmak java.lang.IllegalArgumentExceptionbunların uygulanması ayrıntılarından belirgin olarak çağrıldığında.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.