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,使用更简洁可靠。