Java: Date yapıcısı neden kullanılmıyor ve bunun yerine ne kullanıyorum?


212

C # dünyasından geliyorum, bu yüzden henüz Java ile çok deneyimli değilim. Eclipse Datetarafından artık kullanımdan kaldırıldığı söylendi :

Person p = new Person();
p.setDateOfBirth(new Date(1985, 1, 1));

Neden? Bunun yerine (özellikle yukarıdaki gibi durumlarda) ne kullanılmalıdır?


37
C # 'dan Java' ya da benzer bir öğrenme eğrisi yaşıyorum. Beni ısırtan bir diğer şey ise, yılın ayının 0 tabanlı bir sistem olması (0 ila 11 Ocak = 0 ve Aralık = 11), ancak ayın günlerinin 1 tabanlı (1 ila 31) olmasıdır. Buna dikkat edin!
Paul Sasik

2
@Paul Sasik, evet, ancak Takvim var.JANUARY sabiti örneğin ve her ay için bir tane
Diogo

5
@Atakannozyurt Evet, aptal Java. C # Java ve OMG acı ve sefalet geçmek zorunda kaldı.
cbmeeks


8
.Net mükemmel Java kütüphanesi Joda-Time'ın bir limanından iyi bir tarih-zaman kütüphanesi ( Noda Time ) aldığından C # kişilerinin Java hakkındaki sinsi "lol" yorumları beni güldürdü .
Basil Bourque

Yanıtlar:


98

Spesifik Datekurucu kullanımdan kaldırılmıştır ve Calendarbunun yerine kullanılmalıdır. JavaDociçin Tarih kurucular kaldırılmış olan ve bir kullanarak bunları nasıl değiştirileceği açıklanır Calendar.


25
Takvim fazladan bir nesne gerektirir ve aynı şeyi yapmak için 8 satır daha fazla kod gerektirir ki bu da söyleyebileceğim bir Date nesnesi oluşturur. Kafa karıştırıcıdır ve saat dilimine göre ayarlanmış bir değişkene değil, yalnızca bir Tarihe ihtiyacınız olduğunda gereksiz görünür.
G_V

5
Bilginize gibi korkunç zahmetli eski tarih-saat sınıfları java.util.Date, java.util.Calendarve java.text.SimpleDateFormatşimdi mirası supplanted, java.time sonra Java 8 ve yerleşik sınıflara. Oracle'ın Öğreticisine bakın .
Basil Bourque

250

java.util.DateSınıf aslında diğer kurucular / yöntemler kullanımdan kaldırılmıştır bir çift ile birlikte, sadece bu yapıcı, kaldırılmış değildir. Kullanımdan kaldırıldı çünkü bu tür bir kullanım uluslararasılaşmada iyi çalışmıyor. Bunun Calendaryerine sınıf kullanılmalıdır:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1988);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
Date dateRepresentation = cal.getTime();

Javadoc tarihine bir göz atın:

http://download.oracle.com/javase/6/docs/api/java/util/Date.html


2
Bu en iyi cevap olmalı. Teşekkürler.
jordaniac89

"Uluslararasılaşma ile iyi çalışmaz" diyerek, Date için bunun için TimeZone atayamayacağınızı mı kastediyorsunuz? Teşekkürler
DiveInto

Hangi Tarih bir Dizeyi ayrıştırdı, bunun yerine şimdi yıl, ay ve günü içeren bir Dizeyi alt dizeye almalıyız? Çoğu durumda böyle karmaşık mantığa ve ona eklenen yöntemlere ihtiyaç duymayan bir şey için ekstra güçlük gibi görünüyor.
G_V

1
Sadece eklemek için, bu varsayılan zaman dilimini dikkate alacaktır. Başka bir saat dilimi belirtmek istiyorsak, şunu kullanabilirizCalendar cal = Calendar.getInstance(TimeZone.getTimeZone(<timezone id>));
Vikas Prasad

1
"Bunun yerine Calendar sınıfı kullanılmalıdır" - Java 8 ve üstü için java.time.*sınıflar daha iyi seçenektir ... kodunuzu değiştiriyorsanız.
Stephen C

73

tl; Dr.

LocalDate.of( 1985 , 1 , 1 )

…veya…

LocalDate.of( 1985 , Month.JANUARY , 1 )

ayrıntılar

java.util.Date, java.util.CalendarVe java.text.SimpleDateFormatJava ilk başlatılan ve gelişti zaman sınıflar çok hızlı koştu. Sınıflar iyi tasarlanmamış veya uygulanmamıştır. İyileştirmeler denendi, böylece bulduğunuz itirazlar. Maalesef iyileştirme girişimleri büyük ölçüde başarısız oldu. Sen gerektiğini bu sınıflar önlemek tamamen. Java 8'de yeni sınıflarla desteklenirler.

Kodunuzdaki Sorunlar

Bir java.util.Date'in hem tarih hem de saat bölümü vardır. Kodunuzdaki zaman bölümünü yok saydınız. Date sınıfı, JVM'nizin varsayılan saat dilimi tarafından tanımlanan günün başlangıcını alacak ve o zamanı Date nesnesine uygulayacaktır. Bu nedenle kodunuzun sonuçları, hangi makinede çalıştığına veya hangi saat diliminin ayarlandığına bağlı olarak değişir. Muhtemelen istediğin şey değil.

Sadece tarih istiyorsanız, doğum tarihi gibi saat bölümü olmadan bir Datenesne kullanmak istemeyebilirsiniz . Tarihin yalnızca bir dizesini ISO 8601 biçiminde saklamak isteyebilirsiniz YYYY-MM-DD. Veya LocalDateJoda-Time'dan bir nesne kullanın (aşağıya bakın).

Joda-Time

Java ile öğrenilecek ilk şey: Java ile paketlenmiş kötü şöhretli java.util.Date & java.util.Calendar sınıflarından kaçının .

As doğru belirtildiği user3277382 tarafından cevap , kullanım ya Joda-Time ya da yeni java.time. * Paket Java 8'de.

Joda-Time 2.3 Örnek Kodu

DateTimeZone timeZoneNorway = DateTimeZone.forID( "Europe/Oslo" );
DateTime birthDateTime_InNorway = new DateTime( 1985, 1, 1, 3, 2, 1, timeZoneNorway );

DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" );
DateTime birthDateTime_InNewYork = birthDateTime_InNorway.toDateTime( timeZoneNewYork ); 

DateTime birthDateTime_UtcGmt = birthDateTime_InNorway.toDateTime( DateTimeZone.UTC );

LocalDate birthDate = new LocalDate( 1985, 1, 1 );

Konsola dökümü…

System.out.println( "birthDateTime_InNorway: " + birthDateTime_InNorway );
System.out.println( "birthDateTime_InNewYork: " + birthDateTime_InNewYork );
System.out.println( "birthDateTime_UtcGmt: " + birthDateTime_UtcGmt );
System.out.println( "birthDate: " + birthDate );

Çalıştırıldığında…

birthDateTime_InNorway: 1985-01-01T03:02:01.000+01:00
birthDateTime_InNewYork: 1984-12-31T21:02:01.000-05:00
birthDateTime_UtcGmt: 1985-01-01T02:02:01.000Z
birthDate: 1985-01-01

java.time

Bu durumda java.time kodu Joda-Time koduyla hemen hemen aynıdır .

Bir saat dilimi ( ZoneId) alırız ve bu saat dilimine atanmış bir tarih-saat nesnesi oluştururuz (ZonedDateTime ) . Daha sonra Değişmez Nesneler desenini kullanarak, eski nesnenin aynı anında ( çağdan beri nanosaniye sayısı ) dayalı ancak başka bir saat dilimi atanan yeni tarih saatleri oluştururuz . Son olarak biz almak LocalDatehiçbir zaman günün-de saat diliminde olduğu tarih (yeni gün göründü önce de belirlerken saat dilimi geçerlidir haber olsa olan Oslo daha New York'a örneğin).

ZoneId zoneId_Norway = ZoneId.of( "Europe/Oslo" );
ZonedDateTime zdt_Norway = ZonedDateTime.of( 1985 , 1 , 1 , 3 , 2 , 1 , 0 , zoneId_Norway );

ZoneId zoneId_NewYork = ZonedId.of( "America/New_York" );
ZonedDateTime zdt_NewYork = zdt_Norway.withZoneSameInstant( zoneId_NewYork );

ZonedDateTime zdt_Utc = zdt_Norway.withZoneSameInstant( ZoneOffset.UTC );  // Or, next line is similar.
Instant instant = zdt_Norway.toInstant();  // Instant is always in UTC.

LocalDate localDate_Norway = zdt_Norway.toLocalDate();

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.

Artık bakım modunda olan Joda-Time projesi java.time sınıflarına geçişi tavsiye ediyor .

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 .

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, sınıflara gerek yok .java.sql.*

Java.time sınıflarını nereden edinebilirsiniz?

ThreeTen-Ekstra proje ek sınıfları ile java.time uzanır. Bu proje, java.time'a gelecekteki olası eklemeler için bir kanıt zeminidir. Burada bazı yararlı sınıfları gibi bulabilir Interval, YearWeek, YearQuarter, ve daha .


5
Temel sebepten bahsetmek ve mevcut tüm alternatiflerin kapsamını sağlamak için aksesuarlar.
mabi

Bu doğru cevaptır ve Calendar sınıfından kaçınılmalıdır. ThreeTen en iyi seçenektir
ant2009 16:19

11

Kurucunun kullanımdan kaldırılmasının bir nedeni, year parametresinin anlamının beklediğiniz gibi olmamasıdır. Javadoc diyor ki:

JDK sürüm 1.1 ile değiştirilir Calendar.set(year + 1900, month, date).

Yıl alanının o zamandan beri geçen yıl olduğuna dikkat edin 1900, bu nedenle örnek kodunuz büyük olasılıkla yapmasını beklediğiniz şeyi yapmayacaktır. İşte mesele bu.

Genel olarak, DateAPI yalnızca modern batı takvimini destekler, kendine özgü belirlenmiş bileşenler içerir ve alanları ayarlarsanız tutarsız davranır.

CalendarVe GregorianCalendarAPI'ler daha iyi olan Dateve 3. taraf Joda zamanlı API'leri genellikle iyi olduğu düşünüldü. Java 8'de java.timepaketleri tanıttılar ve bunlar artık önerilen alternatif.


Bu çözüm, yeni Tarih (yıl, ay, gün) gibi saat-dakika-saniye-milisaniye için sıfır zaman kullanmaması dışında harika çalışıyor. Yani şöyle bir şeye ihtiyacımız var: Calendar cal = Calendar.getInstance (); ) (cal.clear; cal.set (yıl + 1900, ay, tarih); Tarih dateRepresentation = cal.getTime ();
Joel Richard Koett

11

Bu soruyu, belirli bir yıl, ay ve günde almak için kullanılmayan yolun ne olduğunu soran yeni bir sorunun kopyası olarak karşımıza çıktı Date.

Şimdiye kadar buradaki yanıtlar Calendarsınıfı kullanmayı söylüyor ve Java 8 çıkana kadar bu doğruydu. Ancak Java 8'den itibaren, bunu yapmanın standart yolu:

LocalDate localDate = LocalDate.of(1985, 1, 1);

Ve gerçekten gerçekten ihtiyacınız java.util.Datevarsa, bu sorudaki önerileri kullanabilirsiniz .

Daha fazla bilgi için, API 8 veya Java 8 eğiticilerine göz atın.


7

Unutmayın ki Calendar.getTime(), gündüz vakti anlamsızdır. parçasının geçerli saati varsayılan .

Çoğaltmak için aşağıdaki kodu birkaç kez çalıştırmayı deneyin:

Calendar c = Calendar.getInstance();
c.set(2010, 2, 7); // NB: 2 means March, not February!
System.err.println(c.getTime());

Çıktı örn .:

Sun Mar 07 10:46:21 CET 2010

Birkaç dakika sonra tam olarak aynı kodu çalıştırmak:

Sun Mar 07 10:57:51 CET 2010

Bu nedenle, set()karşılık gelen alanları değerleri düzeltmeye zorlarken, diğer alanlar için sistem süresini sızdırır. (Yukarıda Sun jdk6 & jdk7 ile test edilmiştir)




2

Tarih yapıcısı kullanımdan kaldırıldığı için bu kodu deneyebilirsiniz.

import java.util.Calendar;

  Calendar calendar = Calendar.getInstance();
     calendar.set(Calendar.HOUR_OF_DAY, 6);// for 6 hour
     calendar.set(Calendar.MINUTE, 0);// for 0 min
     calendar.set(Calendar.SECOND, 0);// for 0 sec
     calendar.set(1996,0,26);// for Date [year,month(0 to 11), date]

    Date date = new Date(calendar.getTimeInMillis());// calendar gives long value

    String mConvertedDate = date.toString();// Fri Jan 26 06:00:00 GMT+05:30 1996

1
Bunlar korkunç sınıflar tarafından yapılmış supplanted yıl önce sahip şimdi eski olan java.time JSR 310 Önerme tanımlanan sınıflar Dateve Calendar2019 yılında fakir bir tavsiye.
Basil Bourque

@BasilBourque öneri için teşekkürler, yakında güncellemek için sabırsızlanıyorum.
Divyanshu Kumar


1

Sınıfı new Date(year,month,date)kullanarak kodunuzda olduğu gibi bir yöntem yapabilirsiniz Calendar.

private Date getDate(int year,int month,int date){
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, year);
    cal.set(Calendar.MONTH, month-1);
    cal.set(Calendar.DAY_OF_MONTH, day);
    return cal.getTime();
}

Tıpkı şu kullanımdan kaldırılan kurucu gibi çalışacak Date


1
Bu korkunç sıkıntılı sınıflar, yıllar önce, modern java.time sınıfları, özellikle Instantve ile tamamlandı ZonedDateTime.
Basil Bourque

Yukarıdaki çözüm yıl için 1900 eklemeli ve aydan 1 ÇIKMAMALIDIR ve Calendar.getInstance () satırından sonra cal.clear () yöntemini çalıştırmalıdır, böylece saat / dakika / saniye / milisaniye sıfırlanır ( Date yapıcısında yaparlar).
Joel Richard Koett

1

Tarih yapıcısı, 1900 yılından bu yana yıl biçiminde, sıfır tabanlı aylar, tek tabanlı günler ve yıl / dakika / saniye / milisaniye sıfıra ayarlar.

Date result = new Date(year, month, day);

Kullanımdan kaldırılmış Tarih yapıcısı için Takvim değişimini (sıfır temelli yıllar, sıfır temelli aylar, bir temelli günler) kullanarak şöyle bir şeye ihtiyacımız var:

Calendar calendar = Calendar.getInstance();
calendar.clear(); // Sets hours/minutes/seconds/milliseconds to zero
calendar.set(year + 1900, month, day);
Date result = calendar.getTime();

Veya Java 1.8 (sıfır tabanlı yıl ve bir tabanlı aylar ve günler) kullanarak:

Date result = Date.from(LocalDate.of(year + 1900, month + 1, day).atStartOfDay(ZoneId.systemDefault()).toInstant());

Tarih, Takvim ve Java 1.8'in eşit sürümleri şunlardır:

int year = 1985; // 1985
int month = 1; // January
int day = 1; // 1st

// Original, 1900-based year, zero-based month, one-based day
Date date1 = new Date(year - 1900, month - 1, day);

// Calendar, zero-based year, zero-based month, one-based day
Calendar calendar = Calendar.getInstance();
calendar.clear(); // Sets hours/minutes/seconds/milliseconds to zero
calendar.set(year, month - 1, day);
Date date2 = calendar.getTime();

// Java-time back to Date, zero-based year, one-based month, one-based day
Date date3 = Date.from(LocalDate.of(year, month, day).atStartOfDay(ZoneId.systemDefault()).toInstant());

SimpleDateFormat format = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss.SSS");

// All 3 print "1985-Jan-01 00:00:00.000"
System.out.println(format.format(date1));
System.out.println(format.format(date2));
System.out.println(format.format(date3));

1
Bu korkunç sınıfların her ikisi de yıllar önce JSR 310'da tanımlanan java.time sınıflarıyla desteklendi.
Basil Bourque

Tarih, Takvim ve Java 1.8 sürümlerini göstermek için cevap güncellendi.
Joel Richard Koett

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.