java 8+ 应使用 java.time 包处理时间日期,优先选用线程安全的 datetimeformatter 和 zoneddatetime;格式化用预定义常量或 ofpattern,时区处理用 zoneid 显式绑定,存储传输统一用 instant,避免 simpledateformat 和 localdatetime 存库。

Java 中时间日期格式化与时区处理的核心是用对 java.time 包(Java 8+),避免老式 Date 和 SimpleDateFormat —— 它们线程不安全、易出错、难以处理时区。
用 DateTimeFormatter 精准格式化本地时间
DateTimeFormatter 是不可变、线程安全的格式化工具,推荐使用预定义常量或自定义模式。
- 常用内置格式:如
DateTimeFormatter.ISO_LOCAL_DATE_TIME(2024-05-20T14:30:45)、DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") - 格式化
LocalDateTime时不带时区信息,适合纯业务时间展示(如订单创建时间) - 避免用字符串拼接或手动截取;若需国际化,搭配
Locale使用:DateTimeFormatter.ofPattern("dd MMM yyyy, HH:mm", Locale.FRANCE)
用 ZonedDateTime 处理带时区的真实时间
真实场景中,“2024-05-20 14:30”在纽约和东京代表不同瞬时(Instant)。必须用 ZonedDateTime 显式绑定时区。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 从系统默认时区构建:
ZonedDateTime.now(ZoneId.systemDefault()) - 指定时区解析字符串:
ZonedDateTime.parse("2024-05-20T14:30:00+09:00[Asia/Tokyo]", DateTimeFormatter.ISO_ZONED_DATE_TIME) - 转换时区不改变实际时刻(Instant):
zdt.withZoneSameInstant(ZoneId.of("America/New_York")) - 注意
withZoneSameLocal()是“强行套用新时区”,会改变对应 Instant,慎用
跨时区存储与传输:统一用 Instant + 时区上下文
数据库和 API 交互应以 Instant 为唯一可信时间基准(UTC 瞬时),显示时再结合用户/业务时区渲染。
- 存入数据库(如 PostgreSQL 的
TIMESTAMP WITH TIME ZONE):用Timestamp.from(instant)或 JPA 的@Column(columnDefinition = "TIMESTAMP WITH TIME ZONE") - 接收前端传来的 ISO 8601 时间(如 2024-05-20T06:30:00Z):直接
Instant.parse(str) - 向用户展示时,根据其偏好时区转换:
instant.atZone(ZoneId.of("Asia/Shanghai")),再格式化 - 不要把
LocalDateTime当“无时区时间”存库——它丢失上下文,后续无法可靠转换
避开常见陷阱
很多问题源于混淆类型语义或误用旧 API。
-
SimpleDateFormat非线程安全:多线程下可能抛异常或返回错误结果;改用DateTimeFormatter -
new Date().getTime()返回毫秒数,本质就是Instant,可直接Instant.ofEpochMilli(ms) - 时区 ID 用
ZoneId.of("Asia/Shanghai"),别用缩写如"CST"(歧义大,JVM 可能映射错误) - 夏令时切换时,
ZonedDateTime自动处理跳变(如 Spring Forward),但LocalDateTime.plusHours(1)不会感知 DST,慎用于跨日计算
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










