使用simpledateformat转换时区需先调用settimezone()设置目标时区(推荐iana id如"asia/shanghai"),再format();date无时区信息,显示时区由格式器决定;simpledateformat非线程安全,高并发应使用threadlocal或java 8+的datetimeformatter。

直接用 SimpleDateFormat 配合 TimeZone.getTimeZone() 就能将时间转成指定时区的字符串,关键在于:先设时区,再格式化;时区必须设在 SimpleDateFormat 实例上,而不是仅靠输入的 Date 对象。
设置时区后再格式化
Date 本身不带时区信息,它只是自 Unix 纪元以来的毫秒数。真正决定显示时区的是 SimpleDateFormat 的时区配置。所以必须调用 setTimeZone() 方法指定目标时区:
- 用
TimeZone.getTimeZone("Asia/Shanghai")获取标准时区对象(推荐用 IANA 时区 ID,如"America/New_York") - 调用
dateFormat.setTimeZone(zone)把时区绑定到格式器上 - 再执行
format(date),输出的就是该时区下的本地时间字符串
注意时区 ID 的写法
TimeZone.getTimeZone() 支持多种输入,但行为不同:
- 推荐用 全名 IANA ID,如
"Asia/Shanghai"、"Europe/London"—— 准确且支持夏令时 - 可用 缩写 如
"CST"、"PST",但有歧义(比如 CST 可指 China Standard Time 或 Central Standard Time),不建议生产环境使用 - 也可用 GMT 偏移,如
"GMT+08:00"或"GMT-05:00",但不自动适配夏令时切换
完整示例代码
把一个 UTC 时间(或任意时间)转为北京时间字符串:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 设为东八区
String result = sdf.format(new Date()); // 输出:2024-06-15 14:30:22(当前北京时间)
如果原始时间是已知的 UTC 时间戳,仍用同一套逻辑 —— Date 对象不变,只改格式器的时区,就能得到对应时区的本地表示。
线程安全提醒
SimpleDateFormat 不是线程安全的。多线程环境下,不要复用同一个实例。常见做法:
- 每次使用都新建(轻量,适合低频)
- 用
ThreadLocal<simpledateformat></simpledateformat>包裹(推荐用于高频场景) - Java 8+ 更推荐用
DateTimeFormatter+ZonedDateTime,天然不可变、线程安全
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











