问题
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