wake-up-neo.net

Java: Warum ist der Date-Konstruktor veraltet und was verwende ich stattdessen?

Ich komme aus der C # Welt, also mit Java noch nicht so erfahren. Wurde gerade von Eclipse gesagt, dass Date veraltet war.

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

Warum? Und was (besonders in Fällen wie oben) sollte stattdessen verwendet werden?

182
Svish

Der spezielle Date-Konstruktor ist veraltet, und stattdessen sollte ein Kalender verwendet werden. Das JavaDoc für Date beschreibt, welche Konstruktoren veraltet sind und wie sie mit einem Kalender ersetzt werden können.

90
Ruben

Die Java.util.Date-Klasse ist nicht wirklich veraltet, nur dieser Konstruktor sowie einige andere Konstruktoren/Methoden sind veraltet. Es wurde nicht mehr empfohlen, da diese Verwendung bei der Internationalisierung nicht gut funktioniert. Die Calendar-Klasse sollte stattdessen verwendet werden:

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

Schauen Sie sich das Datum Javadoc an:

http://download.Oracle.com/javase/6/docs/api/Java/util/Date.html

222
BuffaloBuffalo

tl; dr

_LocalDate.of( 1985 , 1 , 1 )
_

…oder…

_LocalDate.of( 1985 , Month.JANUARY , 1 )
_

Einzelheiten

Die Klassen _Java.util.Date_, _Java.util.Calendar_ und _Java.text.SimpleDateFormat_ wurden zu schnell ausgeführt, als Java zum ersten Mal gestartet und weiterentwickelt wurde. Die Klassen waren nicht gut konzipiert oder implementiert. Es wurde versucht, Verbesserungen vorzunehmen, daher die von Ihnen festgestellten Abwertungen. Leider sind die Verbesserungsversuche weitgehend gescheitert. Sie solltendiese Klassenganz vermeiden. Sie werden in Java 8 durch neue Klassen ersetzt.

Probleme in Ihrem Code

Ein Java.util.Date hat sowohl einen Datums- als auch einen Zeitanteil. Sie haben den Zeitanteil in Ihrem Code ignoriert. Die Date-Klasse nimmt also den Beginn des Tages, wie in der Standardzeitzone Ihrer JVM definiert, und wendet diese Zeit auf das Date-Objekt an. Die Ergebnisse Ihres Codes hängen also davon ab, auf welchem ​​Computer er ausgeführt wird oder welche Zeitzone eingestellt ist. Wahrscheinlich nicht was du willst.

Wenn Sie nur das Datum ohne den Zeitanteil möchten, z. B. für ein Geburtsdatum, möchten Sie möglicherweise kein Date-Objekt verwenden. Möglicherweise möchten Sie nur eine Zeichenfolge des Datums im Format ISO 8601 _YYYY-MM-DD_ speichern. Oder verwenden Sie ein LocalDate Objekt von Joda-Time (siehe unten).

Joda-Zeit

Das Erste, was Sie in Java lernen sollten:Vermeiden Sie die notorisch lästigen Java.util.Date- und Java.util.Calendar-Klassen, die mit Java gebündelt sind.

Verwenden Sie, wie in die Antwort von user3277382 richtig angegeben, entweder Joda-Time oder die neue Java.time . * package in Java 8.

Beispielcode in Joda-Time 2.3

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

Dump to console ...

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

Beim Laufen ...

_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

In diesem Fall ist der Code für Java.time fast identisch mit dem von Joda-Time .

Wir erhalten eine Zeitzone ( ZoneId ) und konstruieren ein Datum-Zeit-Objekt, das dieser Zeitzone zugewiesen ist ( ZonedDateTime ). Mit dem Muster Immutable Objects erstellen wir dann neue Datums- und Uhrzeitangaben basierend auf dem gleichen Zeitpunkt des alten Objekts (Anzahl der Nanosekunden seit Epoche ), aber eine andere Zeitzone zugewiesen. Zuletzt erhalten wir ein LocalDate , das keine Uhrzeit und keine Zeitzone hat. Beachten Sie jedoch, dass die Zeitzone bei der Bestimmung dieses Datums gilt (ein neuer Tag dämmert früher in ) + Oslo als in New York zum Beispiel).

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

Über Java.time

Das Java.time Framework ist in Java 8 und höher integriert. Diese Klassen ersetzen die lästigen alten Legacy Datum-Zeit-Klassen wie Java.util.Date , Calendar , & SimpleDateFormat .

Das Joda-Time -Projekt, das sich jetzt im - Wartungsmodus befindet, rät zur Migration auf Java .time Klassen.

Weitere Informationen finden Sie im Oracle Tutorial . Suchen Sie in Stack Overflow nach vielen Beispielen und Erklärungen. Die Spezifikation lautet JSR 310 .

Sie können Java.time - Objekte direkt mit Ihrer Datenbank austauschen. Verwenden Sie einen JDBC-Treiber , der mit JDBC 4.2 oder höher kompatibel ist. Keine Notwendigkeit für Zeichenfolgen, keine Notwendigkeit für _Java.sql.*_ Klassen.

Woher bekomme ich die Java.time-Klassen?

Das Projekt ThreeTen-Extra erweitert Java.time um zusätzliche Klassen. Dieses Projekt ist ein Testfeld für mögliche zukünftige Ergänzungen von Java.time. Hier finden Sie möglicherweise einige nützliche Klassen wie Interval , YearWeek , YearQuarter , und more .

65
Basil Bourque

Ich kam auf diese Frage als ein Duplikat von einer neueren Frage , in der gefragt wurde, wie die nicht veraltete Möglichkeit, eine Date in einem bestimmten Jahr, Monat und Tag zu erhalten, war.

Die bisherigen Antworten besagen, die Calendar-Klasse zu verwenden, und das war wahr, bis Java 8 herauskam. Ab Java 8 ist dies der Standardweg:

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

Und wenn Sie wirklich einen Java.util.Date brauchen, können Sie die Vorschläge in dieser Frage verwenden.

Weitere Informationen finden Sie unter der API oder den Tutorials für Java 8.

11
Kevin Workman

Ein Grund dafür, dass der Konstruktor veraltet ist, ist, dass die Bedeutung des Jahresparameters nicht so ist, wie Sie es erwarten würden. Der Javadoc sagt:

Ab JDK Version 1.1 ersetzt durch Calendar.set(year + 1900, month, date).

Beachten Sie, dass das Jahrfeld die Anzahl der Jahre seit 1900 ist. Daher wird Ihr Beispielcode höchstwahrscheinlich nicht das tun, was Sie erwarten. Und das ist der Punkt.

Im Allgemeinen unterstützt die Date-API nur den modernen westlichen Kalender, hat idiosynkratisch spezifizierte Komponenten und verhält sich inkonsistent, wenn Sie Felder festlegen.

Die Calendar- und GregorianCalendar-APIs sind besser als Date, und die Joda-time-APIs von Drittanbietern galten allgemein als die besten. In Java 8 wurden die Java.time-Pakete eingeführt, die nun die empfohlene Alternative sind.

9
Stephen C

Bitte beachten Sie, dass Calendar.getTime() nicht deterministisch ist in dem Sinne, dass der Tageszeit Teil auf die aktuelle Zeit eingestellt ist.

Führen Sie folgenden Code ein paar Mal aus, um zu reproduzieren:

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

Ausgabe zB:

Sun Mar 07 10:46:21 CET 2010

Wenn Sie den gleichen Code ein paar Minuten später ausführen, erhalten Sie Folgendes:

Sun Mar 07 10:57:51 CET 2010

Während set() entsprechende Felder zwingt, die Werte zu korrigieren, verliert sie Systemzeit für die anderen Felder. (Oben getestet mit Sun jdk6 & jdk7)

7
Tijn Porcelijn

Date selbst ist nicht veraltet. Es ist nur eine Menge seiner Methoden. Siehe hier für Details .

Verwenden Sie stattdessen Java.util.Calendar .

6
Mike Thomsen

Die meisten Java-Entwickler verwenden derzeit das Drittanbieterpaket Joda-Time . Es wird weithin als eine viel bessere Implementierung betrachtet. 

Java 8 hat jedoch ein neues Java.time. * -Paket . Siehe diesen Artikel, Einführung in die neue Datums- und Uhrzeit-API für JDK 8 .

5
davesbrain

Ähnlich wie von Binnyb vorgeschlagen, sollten Sie die neuere Calendar> GregorianCalendar-Methode in Betracht ziehen. Sehen Sie sich diese neueren Dokumente an:

http://download.Oracle.com/javase/6/docs/api/Java/util/GregorianCalendar.html

1
Joshua
new GregorianCalendar(1985, Calendar.JANUARY, 1).getTime();

(der Vor-Java-8-Weg)

0
Curtis Yallop

Der Date-Konstruktor erwartet Jahre im Format Jahre seit 1900, nullbasierte Monate, und setzt Stunden/Minuten/Sekunden/Millisekunden auf Null.

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

Wenn Sie also die Kalenderersetzung (nullbasierte Jahre, nullbasierte Monate, einbasierte Tage) für den veralteten Date-Konstruktor verwenden, benötigen Sie Folgendes:

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

Oder mit Java 1.8 (mit nullbasiertem Jahr und einbasierten Monaten und Tagen):

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

Hier sind gleiche Versionen von Date, Calendar und Java 1.8:

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

Sie können eine Methode genauso wie new Date(year,month,date) in Ihrem Code erstellen, indem Sie die Klasse Calendar verwenden. 

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

Es funktioniert genauso wie der veraltete Konstruktor von Date 

0
Sudhanshu Dubey