反序列化后,DateTime不等于自身

Dom*_*kis 7 serialization datetime scala jodatime deserialization

正如您在下面看到的,在序列化和反序列化之后,您将获得据称不同的DateTime实例:

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
Run Code Online (Sandbox Code Playgroud)

根据AbstractInstant的javadoc,equals"基于毫秒时刻,时间顺序和时区,将此对象与指定对象进行相等性比较." 所以这不应该发生吗?我错过了什么?

Men*_*ild 13

这是唯一正确的答案,通过自己的测试找到:

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!!!
Run Code Online (Sandbox Code Playgroud)

我假设在Scala中比较by ==确实意味着用equals()进行比较,因为@ aris1348880在他的评论中已经说明了,因此我已经相应地将java代码转换为java代码.

因此失败的原因是equals() - 比较是显而易见的:它是在对象的toString()方法中没有正确打印的时区id .我认为它是JodaTime中的一个错误,因为应该始终打印一个不可变值对象的整个状态.顺便说一句,在这个细节中,旧的更糟糕!好吧,因为你可以使用JodaTime的格式引擎来正确打印出来.DateTimeatoString()java.util.Date

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]
Run Code Online (Sandbox Code Playgroud)

为了使行为更清晰:

DateTime构造函数使用默认时区(在我的测试中为Europe/Berlin).它的toString() - 方法打印偏移,而不是实时区域(这是问题).

DateTime-parse() - 方法根据JodaTime文档使用ISODateTimeFormat #dateTimeParser(),它再次只能解析偏移量,但在这段代码中它也只是偏移信息,而不是真实时区,否则解析会已经停止了例外.

在这两种情况下,DateTime的实例都以不同的方式创建,具有不同的时区/偏移,因此具有不同的时间顺序.所以equals() - 结果乍一看是令人惊讶但可以理解的.


Dom*_*kis 5

我在GitHub上打开了一个问题,这是作者的回答:

很久以前我选择了DateTime的toString格式,并省略了包含值类型的完整状态.结果,两个对象看起来是相同的(通过toString),但它们不是.这是一个错误,因为它引起了这种混乱.不幸的是,它无法纠正.

解析行为也是不幸的,因为它过于关注偏移而在时区上不够(因为ISO-8601不处理时区ID).再说一次,在这里做出改变为时已晚.