问题
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:
- these ARE both typed ZonedDateTime objects
- they are equivalent according to the .isEqual() method..
- 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