文章目录
一、核心功能1. 格式化(Date → String)2. 解析(String → Date)
二、常用构造方法三、日期格式模式四、格式化与解析操作1. 格式化日期2. 解析日期字符串
五、线程安全性问题1. 问题描述2. 原因3. 解决方案
六、区域设置与时区1. 设置区域2. 设置时区
七、高级功能1. 自定义格式2. 修改格式
八、常见错误与解决方案1. 日期解析失败2. 区域设置问题
九、与 Java 8+ 的 `DateTimeFormatter` 对比1. 线程安全性2. API 设计3. 示例代码
十、总结
SimpleDateFormat 是 Java 中用于格式化和解析日期时间的核心类,属于 java.text 包。它允许开发者将 Date 对象转换为特定格式的字符串(如 2025-05-24 23:55:43),或将字符串解析为 Date 对象。由于其灵活性和易用性,SimpleDateFormat 在早期 Java 项目中广泛使用。但需注意,它不是线程安全的,在多线程环境下需谨慎使用。
一、核心功能
1. 格式化(Date → String)
将 Date 对象转换为符合指定格式的字符串,例如:
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatted = sdf.format(now); // 输出: 2025-05-24 23:55:43
2. 解析(String → Date)
将符合特定格式的字符串解析为 Date 对象,例如:
String dateStr = "2025-05-24 23:55:43";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(dateStr); // 解析成功返回 Date 对象
二、常用构造方法
SimpleDateFormat(String pattern)
按指定模式创建格式化器。示例:SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
SimpleDateFormat(String pattern, Locale locale)
指定区域设置(如语言、月份名称)。示例:SimpleDateFormat sdf = new SimpleDateFormat("EEEE", Locale.US); // 输出星期几(如 "Saturday")
SimpleDateFormat(String pattern, TimeZone zone)
指定时区(如 TimeZone.getTimeZone("GMT+8"))。示例:SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", TimeZone.getTimeZone("Asia/Shanghai"));
三、日期格式模式
SimpleDateFormat 使用特定的模式符号表示日期时间的各个部分。以下是常用符号及其含义:
符号含义示例说明G时代(Era)AD公元后(AD)或公元前(BC)y年份2025支持 yy(如 25 表示 2025)M月份05、MayMM 表示两位数(如 05)d日期24dd 表示两位数(如 24)H小时(24小时制)23HH 表示两位数(如 23)h小时(12小时制)11hh 表示两位数(如 11)m分钟55mm 表示两位数(如 55)s秒43ss 表示两位数(如 43)S毫秒123SSS 表示三位数(如 123)E星期几Sat支持长格式(如 Saturday)a上午/下午标识PM区分大小写(如 AM/PM)z时区CST支持长格式(如 China Standard Time)
示例模式"yyyy-MM-dd HH:mm:ss" // 2025-05-24 23:55:43
"yyyy年MM月dd日 EEEE" // 2025年05月24日 星期六
"MMM dd, yyyy h:mm a z" // May 24, 2025 11:55 PM CST
四、格式化与解析操作
1. 格式化日期
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss E");
String formatted = sdf.format(now);
System.out.println("当前时间: " + formatted);
// 输出: 当前时间: 2025-05-24 23:55:43 Saturday
2. 解析日期字符串
String dateStr = "2025-05-24 23:55:43";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = sdf.parse(dateStr);
System.out.println("解析后的日期: " + date);
} catch (ParseException e) {
e.printStackTrace();
}
// 输出: 解析后的日期: Sat May 24 23:55:43 GMT+08:00 2025
五、线程安全性问题
1. 问题描述
SimpleDateFormat 不是线程安全的。在多线程环境中共享同一个 SimpleDateFormat 实例可能导致以下问题:
数据不一致或解析错误。抛出 ArrayIndexOutOfBoundsException 或 NumberFormatException。
2. 原因
SimpleDateFormat 内部使用可变状态(如 Calendar 对象),多个线程同时访问时可能破坏其内部状态。
3. 解决方案
每次使用时创建新实例(性能较低):
public String formatDate(Date date) {
return new SimpleDateFormat("yyyy-MM-dd").format(date);
}
使用 ThreadLocal 保存每个线程的实例:
private static final ThreadLocal
new SimpleDateFormat("yyyy-MM-dd"));
public String formatDate(Date date) {
return tl.get().format(date);
}
使用 Java 8+ 的 DateTimeFormatter(推荐):
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.now();
String formatted = date.format(formatter);
六、区域设置与时区
1. 设置区域
示例:显示星期几的中文名称:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd EEEE", Locale.CHINESE);
System.out.println(sdf.format(new Date())); // 输出: 2025-05-24 星期六
示例:显示英文月份名称:
SimpleDateFormat sdf = new SimpleDateFormat("MMMM yyyy", Locale.ENGLISH);
System.out.println(sdf.format(new Date())); // 输出: May 2025
2. 设置时区
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(sdf.format(new Date()));
// 输出: 2025-05-24 15:55:43 UTC
七、高级功能
1. 自定义格式
使用单引号包裹文本:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss");
System.out.println(sdf.format(new Date())); // 输出: 2025-05-24 at 23:55:43
处理特殊字符:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm 'and' ss 'seconds'");
System.out.println(sdf.format(new Date())); // 输出: 23:55 and 43 seconds
2. 修改格式
动态修改模式:SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.applyPattern("dd/MM/yyyy"); // 修改为 dd/MM/yyyy
System.out.println(sdf.format(new Date()));
八、常见错误与解决方案
1. 日期解析失败
原因:输入字符串与模式不匹配。解决方案:检查模式是否与字符串格式完全一致。// 错误示例:模式与字符串格式不匹配
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.parse("2025/05/24"); // 抛出 ParseException
2. 区域设置问题
原因:未指定区域导致解析失败(如英文格式的月份名称)。解决方案:显式指定区域。SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH);
sdf.parse("May 24, 2025"); // 正确解析
九、与 Java 8+ 的 DateTimeFormatter 对比
1. 线程安全性
SimpleDateFormat:非线程安全。DateTimeFormatter:线程安全(推荐用于新项目)。
2. API 设计
SimpleDateFormat:方法分散,需手动处理异常。DateTimeFormatter:链式调用,支持更丰富的日期时间类型(如 LocalDate、LocalDateTime)。
3. 示例代码
// 使用 DateTimeFormatter 替代 SimpleDateFormat
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
String formatted = now.format(formatter);
System.out.println("当前时间: " + formatted);
十、总结
SimpleDateFormat 是 Java 中处理日期格式化的经典工具,但其线程安全性和区域设置问题需引起重视。对于新项目,建议优先使用 Java 8 引入的 java.time 包(如 DateTimeFormatter),以获得更安全、直观的 API。对于旧代码维护,可通过 ThreadLocal 或重新设计线程逻辑来规避风险。