java - Java OffsetDateTime 不同环境测试中的精度问题
问题描述
我在 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()))
,但是有更好的解决方案吗?
解决方案
您的列在数据库中究竟是如何定义的?它应该具有TIMESTAMP(9) WITH TIME ZONE
数据类型,否则值将四舍五入到微秒。
SQL 标准要求默认的小数秒精度TIMESTAMP
和TIMESTAMP WITH TIME ZONE
数据类型为 6。
Java 8 中的各种.now()
方法最多返回 3 个小数位。由于 Java 9,它们通常返回 6 或 7 位,具体取决于操作系统,并且将来可能会返回更多位(例如,在 Linux 上,9 位可用,但 Java 目前只需要 6 位)。
JSR-310 数据类型最多支持 9 位。包括 H2 在内的一些 DBMS 也支持多达 9 位(很少支持更多)。但其他一些 DBMS 最多只支持 6 位数字。
推荐阅读
- c# - 对基于 LINQ 的列表使用匿名类型而不是 var
- selenium-webdriver - 如果存在多个依赖项,Gradle 如何决定从哪个依赖项中获取类
- stripe-payments - 如何使用 Stripe 收集账单信息
- android - 为什么 Invalidate Cache/Restart 选项会导致 android studio 永久构建?
- javascript - 如何自定义图表js条形图形状?
- ios - 在 UIDatePicker Swift 5 中仅设置特定月份
- git - git如何跟踪文件重命名信息?
- graphdb - 增加graphdb工作台中显示的链接限制?
- c++ - 如果缺少 for 循环的初始化部分会怎样?
- r - 在 R 中使用 gets 包进行指标饱和时创建脉冲指标