Calendar与LocalDateTime互转需借助Instant或ZonedDateTime:Calendar→LocalDateTime先toInstant()再atZone().toLocalDateTime();LocalDateTime→Calendar须指定ZoneId,用GregorianCalendar.from(localDateTime.atZone(zoneId))。

Java 中 Calendar 和 LocalDateTime 互转需要借助中间类型(通常是 Instant 或 ZonedDateTime),因为二者属于不同时间模型:前者是遗留 API,依赖时区和可变状态;后者是 Java 8 引入的不可变、时区中立的现代 API。
Calendar → LocalDateTime
关键在于先获取 Calendar 对应的毫秒时间戳,再结合其时区转换为 Instant,最后转成不带时区的 LocalDateTime(注意:这会丢失时区信息,仅保留本地时刻):
- 调用
calendar.toInstant()得到Instant - 用
calendar.getTimeZone().toZoneId()获取对应的ZoneId - 将
Instant转为ZonedDateTime,再提取LocalDateTime
示例代码:
Calendar calendar = Calendar.getInstance();
LocalDateTime localDateTime = calendar.toInstant()
.atZone(calendar.getTimeZone().toZoneId())
.toLocalDateTime();
LocalDateTime → Calendar
LocalDateTime 本身不含时区,必须显式指定时区才能构造出有意义的 Calendar 实例:
立即学习“Java免费学习笔记(深入)”;
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用
localDateTime.atZone(ZoneId)得到ZonedDateTime - 调用
zdt.toInstant()转为Instant - 通过
GregorianCalendar.from(zdt)或手动设置Calendar的时间字段
推荐使用 GregorianCalendar.from()(更简洁且自动适配时区):
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId zoneId = ZoneId.systemDefault(); // 或指定如 ZoneId.of("Asia/Shanghai")
ZonedDateTime zdt = localDateTime.atZone(zoneId);
Calendar calendar = GregorianCalendar.from(zdt);
注意事项
转换时容易忽略的关键点:
-
LocalDateTime没有时区含义,直接转Calendar必须补上时区,否则结果不确定 -
Calendar的时区影响最终时刻解析,例如Calendar.getInstance(TimeZone.getTimeZone("UTC"))和系统默认时区结果不同 - 避免混用旧 API 的
setTimeInMillis()手动设值,易出错且不易读 - 如果只是做时间计算或展示,优先全程使用
LocalDateTime/ZonedDateTime,减少转换
替代建议
除非对接遗留系统,否则尽量避免使用 Calendar:
- 用
LocalDateTime处理无时区的日期时间(如数据库中的 datetime 字段) - 用
ZonedDateTime处理带时区的完整时刻(如用户本地时间 + 时区) - 用
Instant表示时间线上的绝对点(如日志时间戳、系统计时)
不复杂但容易忽略细节,关键是明确“你真正想表达的时间语义”。

















