【问题标题】:Java OffsetDateTime precision issue in tests on different environmentsJava OffsetDateTime 不同环境测试中的精度问题
【发布时间】:2021-06-15 17:35:37
【问题描述】:

我正在 Spock 中运行测试,尝试比较两个 OffsetDateTime 对象。测试与 H2 数据库集成。我的实体名为 Beacon,它具有 creation_time 属性。这是实体:

@Entity
@Table(name = "beacons")
@Getter
@Setter
public class Beacon {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

    private OffsetDateTime creationTime;
}

然后,Spock 测试,我做以下事情:我创建新的 Beacon 对象:

def beacon = new Beacon(
        id: id,
        creationTime: OffsetDateTime.now()
)

然后我将 Beacon 对象保存在数据库中,我获取它并比较创建时间:

beaconRepository.save(beacon)
def savedBeacon = beaconRepository.findById(id)
beacon.getCreationTime() == savedBeacon.getCreationTime()

现在,在 Unix 和 MacOS 上一切正常,而在 Windows 上,此测试失败,因为 savedBeacon.getCreationTime() 返回的时间比 beacon.getCreationTime() 更精确。为什么会这样?当然,我知道几种解决方法,例如将creationTime定义为OffsetDateTime.now(Clock.tickMillis(ZoneId.systemDefault())),但有没有更好的解决方案?

【问题讨论】:

  • 您的“解决方法”正是您应该这样做的。为什么你认为这不是一个足够好的解决方案?
  • 我还以为是溢出了……
  • 编辑您的问题以报告您的每台计算机上部署的 Java 版本:System.getProperty("java.version")。并发布您找到的真实示例数据。

标签: java h2 spock


【解决方案1】:

您的列在数据库中究竟是如何定义的?它应该具有TIMESTAMP(9) WITH TIME ZONE 数据类型,否则值将四舍五入到微秒。

SQL 标准要求 TIMESTAMPTIMESTAMP WITH TIME ZONE 数据类型的默认小数秒精度为 6。

Java 8 中的各种 .now() 方法最多返回 3 个小数位数。由于 Java 9,它们通常返回 6 位或 7 位,具体取决于操作系统,并且将来可能会返回更多位(例如,在 Linux 上,9 位可用,但 Java 目前只需要 6 位)。

JSR-310 数据类型最多支持 9 位。包括 H2 在内的一些 DBMS 也支持多达 9 位(很少支持更多)。但其他一些 DBMS 最多只支持 6 位。

【讨论】:

    【解决方案2】:

    我建议使用OffsetDateTime.isEqual(),因为它会比较您的日期的Instance 表示,这正是您的实际目标。

    【讨论】:

    • 我相信它不会改变结果——对象的精度不同,所以 isEqual 也会返回 false
    • 请看isEqual()的源码,它会回答你的问题。 SPOILER - 它统一了精确度。
    • 精度的统一在哪里? public boolean isEqual(OffsetDateTime other) { return toEpochSecond() == other.toEpochSecond() && toLocalTime().getNano() == other.toLocalTime().getNano(); }
    • 完全正确 - 一切都转换为纳秒精度。
    • 如果一个时间戳只有第二个精度,那么getNano() 将简单地返回0,而另一个时间戳将返回与0 不同的东西,所以 wojtekt 说过,它不会帮助你。您必须反过来,将另一个时间戳截断到相同的精度。如果一个时间戳只有毫秒/微秒精度,则基本原则也适用。
    猜你喜欢
    • 2020-05-23
    • 2019-10-02
    • 2011-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多