SimpleDateFormat 类是 Java 中用于日期时间与字符串之间相互转换的类,它基于 DateFormat 抽象类进行实现的,支持自定义格式化时的格式模式,例如 yyyy-MM-dd HH:mm:ss 格式模式将日期格式化为类似“2024-09-12 12:20:40”格式的字符串。在 JDK 1.8 之前,是处理日期格式化的主要工具。

SimpleDateFormat 的核心作用是:
将 Date 或 Calendar 对象格式化为指定模式的字符串(格式化)
将字符串按指定模式解析为 Date 对象(解析)
示例:下面示例介绍了 SimpleDateFormat 的基础用法
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatExample {
public static void main(String[] args) {
// 1. 定义日期格式模式(区分大小写,常用字母:y-年, M-月, d-日, H-24时, h-12时, m-分, s-秒)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 2. 格式化:Date -> String
Date now = new Date();
String formattedDate = sdf.format(now);
System.out.println("格式化后的日期: " + formattedDate); // 例如:2023-10-05 14:30:25
// 3. 解析:String -> Date(需处理ParseException异常)
String dateStr = "2024-02-29 08:15:30";
try {
Date parsedDate = sdf.parse(dateStr);
System.out.println("解析后的Date对象: " + parsedDate); // 输出对应时间的Date
} catch (ParseException e) {
// 当字符串格式与模式不匹配时抛出异常
System.out.println("日期解析失败: " + e.getMessage());
}
// 演示其他格式
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 a hh:mm");
System.out.println("其他格式: " + sdf2.format(now)); // 例如:2023年10月05日 下午 02:30
}
}运行结果:
格式化后的日期: 2025-09-01 22:43:20 解析后的Date对象: Thu Feb 29 08:15:30 CST 2024 其他格式: 2025年09月01日 下午 10:43
示例说明:
模式字母区分大小写(如 M 代表月份,m 代表分钟)
格式化(format()):将 Date 对象转换为指定格式的字符串
解析(parse()):将字符串按指定格式转换为 Date 对象,需捕获 ParseException
常见模式示例:
yyyy-MM-dd → 2023-10-05
HH:mm:ss → 14:30:25
yyyy年MM月dd日 → 2023 年 10 月 05 日
注意:SimpleDateFormat 是非线程安全的,多线程环境下需额外处理或使用 DateTimeFormatter(Java 8+ 推荐)。
格式化时需使用特定字符表示日期时间元素,常用模式符如下:
y:年(如 yyyy 表示 4 位年,yy 表示 2 位年)
M:月(MM 表示 2 位月,MMM 表示英文月份缩写)
d:日(dd 表示 2 位日)
H:24 小时制小时(HH)
h:12 小时制小时(hh)
m:分钟(mm)
s:秒(ss)
S:毫秒(SSS)
a:上午 / 下午(如 AM/PM)
format() 方法用于将 Date 对象转换为指定格式的字符串。示例:
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatExample1 {
public static void main(String[] args) {
// 创建格式化对象,指定模式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 格式化当前时间
Date now = new Date();
String formattedDate = sdf.format(now);
System.out.println("格式化结果:" + formattedDate); // 如:2023-10-05 14:30:25
}
}运行结果:
格式化结果:2025-09-01 22:49:54
parse() 方法用于将字符串按指定模式解析为 Date 对象(需处理 ParseException)。示例:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatExample2 {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
String dateStr = "2024年03月15日";
try {
// 解析字符串为Date对象
Date date = sdf.parse(dateStr);
System.out.println("解析结果:" + date); // 如:Fri Mar 15 00:00:00 CST 2024
} catch (ParseException e) {
e.printStackTrace(); // 解析失败时处理异常
}
}
}运行结果:
解析结果:Fri Mar 15 00:00:00 CST 2024
setTimeZone() 方法用来指定格式化 / 解析时使用的时区(默认使用系统时区)。示例:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class SimpleDateFormatExample3 {
public static void main(String[] args) {
Date now = new Date();
// 默认时区,东八区,北京时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("当前时间:" + sdf.format(now));
// 设置为UTC时区
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf2.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC时间:" + sdf2.format(now));
}
}运行结果:
当前时间:2025-09-01 22:48:26 UTC时间:2025-09-01 14:48:26
包含毫秒和上午 / 下午标识,例如:
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateFormatExample4 {
public static void main(String[] args) {
// 创建SimpleDateFormat实例,指定格式为"年/月/日 时:分:秒.毫秒 上午/下午"
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS a");
// 获取当前日期时间
Date currentDate = new Date();
// 格式化日期时间
String formattedDate = sdf.format(currentDate);
// 输出格式化结果
System.out.println("格式化后的日期时间: " + formattedDate);
// 演示不同时间的格式化
demonstrateDifferentDates();
}
// 演示不同日期的格式化效果
private static void demonstrateDifferentDates() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.SSS a");
// 创建几个不同的时间点(使用时间戳)
Date morning = new Date(1696500000000L); // 2023年10月5日 上午
Date afternoon = new Date(1696550000000L); // 2023年10月5日 下午
Date midnight = new Date(1696454400000L); // 2023年10月5日 午夜
System.out.println("\n不同时间点的格式化示例:");
System.out.println("上午时间: " + sdf.format(morning));
System.out.println("下午时间: " + sdf.format(afternoon));
System.out.println("午夜时间: " + sdf.format(midnight));
}
}运行结果:
格式化后的日期时间: 2025/09/01 10:47:39.006 下午 不同时间点的格式化示例: 上午时间: 2023/10/05 06:00:00.000 下午 下午时间: 2023/10/06 07:53:20.000 上午 午夜时间: 2023/10/05 05:20:00.000 上午
线程不安全:SimpleDateFormat 的内部状态会被格式化 / 解析操作修改,多线程共享实例时会导致数据错乱。解决方式:
每个线程创建独立实例
使用 ThreadLocal 存储实例
import java.text.SimpleDateFormat;
import java.util.Date;
public class ThreadSafeDateFormatter {
// 使用ThreadLocal存储SimpleDateFormat实例,确保线程安全
private static final ThreadLocal<SimpleDateFormat> sdfThreadLocal =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
/**
* 将日期格式化为"yyyy-MM-dd"字符串
* @param date 要格式化的日期
* @return 格式化后的日期字符串
*/
public static String formatDate(Date date) {
// 从ThreadLocal中获取当前线程的SimpleDateFormat实例
return sdfThreadLocal.get().format(date);
}
/**
* 清理当前线程的ThreadLocal资源
* 注意:在使用线程池时,建议在任务结束时调用此方法
*/
public static void clean() {
sdfThreadLocal.remove();
}
public static void main(String[] args) {
// 演示多线程环境下使用
for (int i = 0; i < 5; i++) {
new Thread(() -> {
try {
// 每个线程获取当前日期并格式化
Date currentDate = new Date();
String formattedDate = formatDate(currentDate);
System.out.println("线程 " + Thread.currentThread().getName() + " 格式化结果: " + formattedDate);
// 模拟线程处理其他任务
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 清理资源
clean();
}
}).start();
}
}
}运行结果:
线程 Thread-2 格式化结果: 2025-09-01 线程 Thread-4 格式化结果: 2025-09-01 线程 Thread-1 格式化结果: 2025-09-01 线程 Thread-0 格式化结果: 2025-09-01 线程 Thread-3 格式化结果: 2025-09-01
解析异常处理繁琐:parse() 方法强制抛出 ParseException,即使格式正确也需显式处理,增加代码冗余。
对新日期类支持不足:不直接支持 JDK 1.8 引入的 java.time 类(如 LocalDateTime),需通过中间对象转换。
SimpleDateFormat 是传统日期格式化工具,但因线程不安全和设计缺陷,JDK 1.8 后推荐使用 java.time.format.DateTimeFormatter,它是线程安全的,且支持新日期时间 API,使用更简洁可靠。