System.currentTimeMillis() 与 LocalDateTime 不能直接转换,需通过 Instant 和 ZoneId 桥接:前者转后者须指定时区得到 ZonedDateTime 再提取;后者转前者须先绑定时区再转 Instant 获取毫秒值。

System.currentTimeMillis() 返回的是自 1970-01-01 00:00:00 UTC(即 Unix 时间戳)起经过的毫秒数,类型是 long;LocalDateTime 是 Java 8 引入的不带时区、不含时间偏移的日期时间类,只表示“年-月-日 时:分:秒.纳秒”,不对应具体时刻。二者不能直接等价转换,必须借助带时区的中间类型(如 Instant 或 ZonedDateTime)来桥接。
从 currentTimeMillis 转 LocalDateTime
需指定一个时区,因为同一毫秒数在不同时区对应不同的本地时间。
- 先用
Instant.ofEpochMilli(millis)转成瞬时时间点 - 再通过
atZone(ZoneId)转为带时区的ZonedDateTime - 最后调用
toLocalDateTime()提取本地时间部分
常用写法(以系统默认时区为例):
long millis = System.currentTimeMillis();LocalDateTime ldt = Instant.ofEpochMilli(millis)
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
从 LocalDateTime 转 currentTimeMillis
LocalDateTime 本身不含时区信息,必须明确它所属的时区,否则无法映射到绝对时间点。
- 用
atZone(ZoneId)将其绑定到某个时区,得到ZonedDateTime - 再调用
toInstant().toEpochMilli()获取毫秒值
例如按北京时间(Asia/Shanghai)转换:
LocalDateTime ldt = LocalDateTime.now();long millis = ldt.atZone(ZoneId.of("Asia/Shanghai"))
.toInstant()
.toEpochMilli();
常见误区提醒
- 不要直接用
LocalDateTime.now().atZone(ZoneId.of("UTC"))替代当前时间戳——这会把本地时间强行解释为 UTC 时间,导致结果偏差 8 小时(对东八区而言) - 避免使用已废弃的
Date或Calendar中间转换,容易出错且可读性差 - 若业务逻辑中频繁混用两者,建议统一使用
Instant表示时间点,用LocalDateTime仅作展示用途
推荐实践方式
如果目标是记录或传输时间点,优先使用 Instant;如果只是格式化显示或做日期计算(如“本月第一天”),才用 LocalDateTime。转换时始终显式声明时区,不依赖系统默认值,便于测试和跨环境部署。

















