You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用java.time.Duration.between计算时间差抛出ZonedDateTime异常排查

问题:使用java.time计算时间戳与本地时间差值时抛出异常

我想计算毫秒级时间戳与本地当前时间的差值,尝试用标准java.time API实现,代码如下:

val eventTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(epochinMilis), ZoneId.systemDefault())
val now = LocalDateTime.now.atZone(ZoneId.systemDefault())
Duration.between(now, eventTime).toHours

执行时抛出如下异常:

java.time.DateTimeException: Unable to obtain ZonedDateTime from TemporalAccessor: 2023-06-26T22:26:36.917 of type java.time.LocalDateTime
at java.base/java.time.ZonedDateTime.from(ZonedDateTime.java:566)
at java.base/java.time.ZonedDateTime.until(ZonedDateTime.java:2130)
at java.base/java.time.Duration.between(Duration.java:490)

改用以下代码可得到预期结果:

now = LocalDateTime.now.atZone(ZoneId.systemDefault())
(epochinMilis/1000 - now.toEpochSecond()) / 3600

我想知道使用标准API时出错的原因是什么?


错误原因分析

核心问题是**Duration.between要求两个入参必须是包含瞬时/时区信息的同类型时间对象**:

  • 你的代码中,eventTime是LocalDateTime类型——仅包含日期和时间,没有时区或偏移信息,属于“本地时间”,不代表某个确定的时刻;
  • 而now是ZonedDateTime类型——包含时区信息,是一个确定的全球瞬时时刻;
  • 当Duration.between尝试计算两者差值时,需要将两个对象转换为同一类型,但LocalDateTime没有时区信息,无法被转换为ZonedDateTime(同一本地时间在不同时区对应不同的瞬时时刻),因此抛出DateTimeException。

正确的标准API实现方式

只需将两个时间对象统一为包含瞬时信息的类型即可,推荐两种写法:

方式1:统一为ZonedDateTime

val eventTime = Instant.ofEpochMilli(epochinMilis).atZone(ZoneId.systemDefault())
val now = ZonedDateTime.now(ZoneId.systemDefault())
val hoursDiff = Duration.between(now, eventTime).toHours()

方式2:直接使用Instant(更高效,因为时间戳本质是瞬时值)

val eventInstant = Instant.ofEpochMilli(epochinMilis)
val nowInstant = Instant.now()
val hoursDiff = Duration.between(nowInstant, eventInstant).toHours()

内容的提问来源于stack exchange,提问作者dr jerry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 22:15:08