SimpleDateFormat早期Java 日期格式化工具详解
SimpleDateFormat早期Java 日期格式化工具详解
你提到的 SimpleDateFormat
通常指 Java 中的 java.text.SimpleDateFormat
类(注意首字母大写,可能是拼写笔误)。它是 Java 早期用于格式化(Date → 字符串)和解析(字符串 → Date)日期时间的核心工具类,基于指定的模式字符串(Pattern)定义日期时间的输出或输入格式。
核心功能
SimpleDateFormat
的核心是通过模式字符串(由特定字符组成的模板)来定义日期时间的格式,支持两种操作:
- 格式化(Format):将
java.util.Date
对象转换为指定格式的字符串。 - 解析(Parse):将符合模式的字符串转换为
java.util.Date
对象。
模式字符串(Pattern)
模式字符串由预定义的字符组成,每个字符代表日期时间的不同部分。常见模式字符如下(区分大小写):
字符 | 含义 | 示例 |
---|---|---|
y | 年(Year) | yyyy → 2025(4位年);yy → 25(2位年) |
M | 月(Month) | MM → 08(2位月);M → 8(1位月);MMM → Aug(英文缩写);MMMM → August(英文全称) |
d | 日(Day) | dd → 04(2位日);d → 4(1位日) |
H | 小时(24小时制,Hour) | HH → 14(2位);H → 2(1位,如凌晨2点) |
h | 小时(12小时制,Hour) | hh → 02(下午2点);h → 2(1位) |
m | 分钟(Minute) | mm → 59(2位);m → 9(1位) |
s | 秒(Second) | ss → 59(2位);s → 9(1位) |
S | 毫秒(Millisecond) | SSS → 999(3位);S → 9(1位) |
E | 星期(Day of Week) | E → 周一;EEEE → 星期一(全称);EEE → 周一(缩写) |
a | 上午/下午标记(AM/PM) | a → 下午 |
z | 时区(Time Zone) | z → GMT+8;zzzz → 中国标准时间 |
基础使用示例
1. 格式化(Date → 字符串)
import java.text.SimpleDateFormat;
import java.util.Date;public class SimpleDateFormatDemo {public static void main(String[] args) {// 创建 SimpleDateFormat 对象,指定模式SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS E a z");// 获取当前时间Date now = new Date();// 格式化为字符串String formatted = sdf.format(now);System.out.println("格式化结果: " + formatted); // 输出示例: 2025-08-04 14:52:59.123 周一 下午 GMT+8}
}
2. 解析(字符串 → Date)
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class ParseDemo {public static void main(String[] args) {String dateStr = "2025-08-04 14:52:59.123";SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");try {// 解析字符串为 Date 对象Date parsedDate = sdf.parse(dateStr);System.out.println("解析后的 Date: " + parsedDate); // 输出示例: Mon Aug 04 14:52:59 CST 2025(CST 是中国标准时间)} catch (ParseException e) {e.printStackTrace(); // 字符串格式与模式不匹配时会抛异常}}
}
关键注意事项
1. 线程不安全
SimpleDateFormat
不是线程安全的!它的内部状态(如日历对象 Calendar
)会被多线程共享修改,导致数据混乱或异常。
常见错误场景:在多线程中共享同一个 SimpleDateFormat
实例(例如作为类的静态变量)。
解决方案:
- 避免共享实例:每次使用时新建
SimpleDateFormat
(性能较差)。 - 使用
ThreadLocal
缓存:为每个线程分配独立的实例。 - 升级到 Java 8+ 的
DateTimeFormatter
(线程安全,推荐)。
2. 模式与字符串必须严格匹配
解析时,输入的字符串必须完全符合模式定义的格式(包括分隔符、位数、字符类型),否则会抛出 ParseException
。
示例:
- 模式
"yyyy-MM-dd"
只能解析"2025-08-04"
,无法解析"2025/08/04"
或"2025年8月4日"
。
3. 时区和语言环境的影响
SimpleDateFormat
默认使用系统的时区和语言环境(如月份/星期的英文缩写)。- 若需指定时区或语言,可通过构造方法设置:
// 指定时区为 UTC SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sdf.setTimeZone(TimeZone.getTimeZone("UTC"));// 指定语言环境为中文(用于月份/星期的中文显示) SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 E", Locale.CHINA);
替代方案:Java 8+ 的 DateTimeFormatter
Java 8 引入的 java.time
包(如 LocalDateTime
、ZonedDateTime
)提供了更现代的日期时间API,其中 DateTimeFormatter
完全替代了 SimpleDateFormat
,且线程安全、设计更简洁。
示例对比:
// Java 8+ 的 DateTimeFormatter(线程安全)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
LocalDateTime now = LocalDateTime.now();
String formatted = now.format(formatter); // 格式化LocalDateTime parsedDate = LocalDateTime.parse("2025-08-04 14:52:59.123", formatter); // 解析
总结
SimpleDateFormat
是 Java 早期的日期格式化工具,核心是通过模式字符串定义日期格式,但存在线程不安全的缺陷。在实际开发中:
- 若使用 Java 8 及以上版本,优先选择
DateTimeFormatter
; - 若必须使用
SimpleDateFormat
,需注意线程安全问题(如通过ThreadLocal
或局部变量)。