如何规范ZonedDateTime以便.equals()工作? [英] How to normalise ZonedDateTime so that .equals() works?

查看:117
本文介绍了如何规范ZonedDateTime以便.equals()工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有类似的代码:

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")
  }
}

可在此处找到代码: https://ideone.com/43zf8B

问题:

  1. 这些都是类型的ZonedDateTime对象
  2. 根据.isEqual()方法,它们是等效的.
  3. 根据.equals()方法,它们不等效

但是我的测试套件使用beEquals进行深度匹配 对这些datetime实例进行的类的操作 因此,我需要一种将它们标准化的方法,以便 .equals()返回true.

请问如何将它们标准化?

解决方案

如果用ZonedDateTime.of(2018, 1, 1, 10, 0, 0, 0, ZoneOffset.UTC)创建zdt1,则两个对象在equals()下是相等的(在Java中仍然不在==下).

显然,当区域名称不同时,使区域相等是不够的.通过使用ZoneOffset.UTC构造第一个ZonedDateTime,两者将具有相同的时区,因此将相等.进行更改后,至少在Mac上,zdt1.getZone() == zdt2.getZone()现在评估为true.

作为对问题的更直接答案,您可以按以下方式规范化ZonedDateTime对象(带有分号的Java语法,请自行翻译):

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

当然,与zdt2类似. ZoneId.normalized()承诺在可能的情况下返回ZoneOffset,这取决于您的情况.因此,在您的情况下,它确实使两个对象在equals()下相等.在所有其他情况下,我都不确定.

一种比较安全的方法是让比较显式地处理不同但相等的时区:

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

这将使用您问题中的两个日期时间计算为true.

BTW

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?

解决方案

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.

这篇关于如何规范ZonedDateTime以便.equals()工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆