2014-01-08 12 views
6

Wie Sie unten sehen können, nachdem die Serialisierung und deserialisieren, erhalten Sie Datetime-Instanzen, die angeblich unterschiedlich sind:Datetime nicht selbst gleich nach Deserialisierung

scala> import org.joda.time.DateTime 
import org.joda.time.DateTime 

scala> val a = new DateTime() 
a: org.joda.time.DateTime = 2014-01-08T19:00:08.883+02:00 

scala> val b = DateTime.parse(a.toString()) 
b: org.joda.time.DateTime = 2014-01-08T19:00:08.883+02:00 

scala> a == b 
res0: Boolean = false 

Per AbstractInstant's javadocequals dieses Objekt mit dem angegebenen Objekt vergleicht für die Gleichheit basierend auf der Millisekunde Zeit, Chronologie und Zeitzone. " Also sollte das nicht richtig passieren? Was vermisse ich?

+1

könnte es sein, weil Sie mit '==' anstelle von 'equals' vergleichen? – gtgaxiola

+0

Versuchen Sie mit 'equals' –

+0

Wenn Sie Scala verwenden, wie es scheint, können Sie Ihre Frage entsprechend markieren, um Verwirrung zu vermeiden. –

Antwort

11

Hier ist die einzige richtige Antwort, durch eigene Tests gefunden:

DateTime a = new DateTime(); // uses default time zone 
System.out.println(a); // 2014-01-08T19:38:00.696+01:00 

DateTime b = DateTime.parse(a.toString()); 
System.out.println(b); // 2014-01-08T19:38:00.696+01:00 

System.out.println(a.getChronology()); // ISOChronology[Europe/Berlin] 
System.out.println(b.getChronology()); // ISOChronology[+01:00] 
System.out.println(a.equals(b)); // false!!! 

ich angenommen habe in Scala, dass der Vergleich von == bedeutet in der Tat Vergleich von equals() als @ aris1348880 hat in seinem Kommentar erwähnt, Daher habe ich in der Übersetzung den Java-Code entsprechend dem Operator ersetzt.

So ist die Ursache der fehlgeschlagenen equals() - Vergleich liegt auf der Hand: Es ist die Zeitzone-ID, die nicht korrekt a im toString() -Methode von DateTime Objekt gedruckt wird. Ich betrachte es als einen Fehler in JodaTime, weil toString() immer den gesamten Status eines unveränderlichen Wertobjekts drucken sollte. Übrigens, in diesem Detail ist das alte java.util.Date noch schlechter! Nun, als Workaround können Sie die Format-Engine von JodaTime verwenden, um korrekt auszudrucken.

Das Datetime-Konstruktor verwendet die Standard-Zeitzone (in meinem Test Europe/Berlin):

System.out.println(
    DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'['ZZZ']'").print(a)); 
// Output: 2014-01-08T19:38:00.696[Europe/Berlin] 

Um das Verhalten deutlicher zu machen. Seine toString() - Methode druckt stattdessen den Offset, nicht die Echtzeitzone (das ist das Problem).

Die DateTime-parse() - Methode verwendet gemäß der JodaTime-Dokumentation ISODateTimeFormat#dateTimeParser(), die wiederum nur Offsets parsen kann, aber in diesem Code wurde sie auch nur mit Versatzinformationen gespeist, nicht mit der Echtzeitzone, sonst würde das Parsing habe mit einer Ausnahme aufgehört.

In beiden Fällen werden Instanzen von DateTime mit unterschiedlichen Zeitzonen/Offsets und damit unterschiedlichen Chronologien erstellt. So ist das equals() - Ergebnis auf den ersten Blick erstaunlich, aber verständlich.

+1

Es scheint mir, dass der Fehler mit 'Parse 'ist, die nicht die Standardzeitzone verwendet ... aber das Parsen eines Datums, das aus einer 'toString'-Methode kommt, ist ziemlich seltsam. –

+1

@ JonathanDrapeau Nein, die Parsemethode ist korrekt, weil sie die Zeitzonenzeichenfolge "+01: 00" liest und sie nur als Offset behandelt, soweit in Ordnung (Zeitzoneninformationen im Text müssen Vorrang vor der Zeitzoneneinstellung im Formatierungsprogramm haben) Objekt). Aber sonst stimme ich zu, dass das ganze Verfahren irgendwie seltsam ist. Ich würde es auch nicht als "Deserialisierung" bezeichnen, genauso wie das Formatieren und Reparieren. –

+0

Wenn Sie komplexe Typen wie DateTime verwenden, ist es besser zu vermeiden, generische Methoden zum Erstellen von Objekten zu verwenden. Im Beispiel ist das Problem mit der Zeitzone, aber Millis sind die gleichen, also a.compareTo (b) == 0. Gleichheit für einen komplexen Typ ist nicht immer ein einfaches Konzept als Gleichheit für den Zustand einer Objektinstanz eines solchen Typs. Zum Beispiel BigDecimal Gleichheit ist nicht das gleiche wie compareTo (on value), weil Gleichheitsprüfung Wert und Skalierung während compareTo nur Wert so neue BigDecimal ("1.0"). Gleich (new BigDecimal ("1.00") ist falsch, während new BigDecimal ("1.0 ") .compareTo (new BigDecimal (" 1.00 ") == 0. – Aris2World

-1

== wird Referenz vergleichen, equals() vergleicht Werte. Versuchen a.equals(b)

Schauen Sie sich diesen Beitrag: What is the difference between == vs equals() in Java?

+3

Nachdem wir Scala-Jungs über die Bedeutung von == in Scala kommentiert haben, scheint diese Antwort nicht richtig zu sein. Aber selbst 'equals()' erzeugt falsch, wie ich in meinem Test bewiesen habe, sehe meine Antwort. –

+0

Das gilt für Java, wohingegen in scala '==()', das ein Aufruf von 'equals()' ist, Werte vergleicht und ['x.eq (y)' prüft, ob 'y' ein Verweis auf' x' ist ] (http://stackoverflow.com/questions/6835578/scala-reference-equality). –

3

Ich habe nicht org.joda.time.DateTime aber ich habe gerade versucht, einen Test mit java.util.Date.

Sie sollten dies versuchen:

val a = new DateTime() 
val b = new DateTime(a.getMillis()) 
a == b 

Ich habe auch versucht dies:

import org.joda.time.DateTime; 

public class TestDateTime { 

    public static void main(String[] args) { 
     DateTime a = new DateTime(); 
     System.out.println(a.toString()); 
     DateTime b = DateTime.parse(a.toString()); 
     System.out.println(b.toString()); 
     System.out.println(a.equals(b)); 
    } 
} 

und dies ist die Ausgabe:

2014-01-08T19:05:52.182+01:00 
2014-01-08T19:05:52.182+01:00 
false 

Und das Problem ist, dass gleich von Datetime versagt weil andere Zeitzone. Ich denke, es ist falsch, die Äquivalenz von zwei DateTime-Instanzen anzunehmen, die auf diese Weise erstellt wurden.

Wenn Sie eine java.util.Date serialisieren und deserialisieren, wird der long (der umbrochene Wert) nicht als String übergeben.

+0

Entschuldigung warum -2? ist es für == statt gleich? Weißt du nicht, dass mit Scala-Interpreter a == b bedeutet a.equals (b)? siehe http://stackoverflow.com/questions/7681161/whats-the-difference-between-and-equals-in-scala – Aris2World

+3

Mein upvote für Sie zu beweisen, dass die Ursache nicht die Verwendung von scala Operator == ist. –

+0

Die Verkleinerung dieser Methode besteht darin, dass Sie kein lesbares serialisiertes Datum mehr haben. –

4

öffnete ich ein Problem auf GitHub, here is the author's response:

vor langer Zeit das toString Format Datetime wählte ich, und ich weggelassen, um den vollen Zustand des Werttypen aufzunehmen. Als Ergebnis sehen zwei Objekte aus, als wären sie gleich (by toString), aber sie sind nicht gleich. Das war ein Fehler, der diese Art von Verwirrung verursacht. Leider kann es nicht korrigiert werden.

Das Parsing-Verhalten ist auch bedauerlich, da es sich zu sehr auf den Offset und nicht genug auf die Zeitzone konzentriert (da ISO-8601 keine Zeitzonen-IDs verarbeitet). Auch hier ist es zu spät, um Änderungen vorzunehmen.

Verwandte Themen