How to normalise ZonedDateTime so that .equals() works?

假装没事ソ 提交于 2020-01-04 00:19:49

问题


I have code, similar to this:

import java.time._

object app {
  def main (args :Array[String]) = {
    println("app started")

    // create two ZonedDateTime objects for 1st Jan 2018, 10am UTC
    // using separate methods
    val zdt1 = ZonedDateTime.of(2018, 1, 1, 10, 0, 0, 0, ZoneId.of("UTC"))
    val zdt2 = ZonedDateTime.parse("2018-01-01T10:00:00Z")

    println(s"COMPARING: $zdt1 and $zdt2")
    println("== check:      " + (zdt1 == zdt2))
    println(".equals check: " + (zdt1.equals(zdt2)))
    println(".isEqual check " + (zdt1.isEqual(zdt2)))

    println("app finished")
  }
}

Code available here: https://ideone.com/43zf8B

The issue:

  1. these ARE both typed ZonedDateTime objects
  2. they are equivalent according to the .isEqual() method..
  3. they are not equivalent according to .equals() method

However my test suite uses deep matching using beEquals operations against the classes these datetime instances are in, therefore I need a way to normalise them so that .equals() returns true.

how can I normalise them please?


回答1:


If I create zdt1 with ZonedDateTime.of(2018, 1, 1, 10, 0, 0, 0, ZoneOffset.UTC), the two objects are equal under equals() (still not under == in Java).

Apparently it’s not enough for the zones to be equivalent when their names are different. By using ZoneOffset.UTC for constructing the first ZonedDateTime, both will have the same time zone and will thus be equal. With my change, at least on my Mac, zdt1.getZone() == zdt2.getZone() now evaluates to true.

As a more direct answer to your question, you may normalize your ZonedDateTime objects this way (Java syntax with semicolon, please translate yourself):

    zdt1 = zdt1.withZoneSameInstant(zdt1.getZone().normalized());

Similarly for zdt2, of course. ZoneId.normalized() promises to return a ZoneOffset where possible, which it is in your case. So in your case it does make two objects that are equal under equals(). I’m not sure it will in all other cases.

A safer way would be to have the comparison explicitly take care of different but equal time zones:

zdt1.toInstant().equals(zdt2.toInstant())
        && zdt1.getZone().getRules().equals(zdt2.getZone().getRules())

This evaluates to true with your two date-times from the question.

BTW isEqual() compares the instants in time only, not the zones at all, which is why it didn’t care.




回答2:


ZoneOffset.UTC

What about the predefined constant ZoneOffset.UTC?

val zdt1 = ZonedDateTime.of(2018, 1, 1, 10, 0, 0, 0, ZoneOffset.UTC)
val zdt2 = ZonedDateTime.parse("2018-01-01T10:00:00Z")

All three methods return true(==, equals and isEqual)



来源:https://stackoverflow.com/questions/48379995/how-to-normalise-zoneddatetime-so-that-equals-works

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!