悠悠楠杉
Java日期时间格式化与解析实战指南
一、传统方案:SimpleDateFormat类
作为Java早期版本的主力日期格式化工具,SimpleDateFormat
至今仍在许多遗留系统中广泛使用。这个位于java.text
包下的类,通过特定的模式字符串来定义日期格式:
java
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedDate = sdf.format(new Date()); // 格式化
Date parsedDate = sdf.parse("2023-08-20 14:30:00"); // 解析
核心模式符号:
- y
:年份(yyyy表示四位年份)
- M
:月份(MM表示两位数月份)
- d
:日期
- H
:24小时制小时
- m
:分钟
- s
:秒钟
典型问题与解决方案:
1. 线程安全问题:每个线程应创建独立实例
java
ThreadLocal<SimpleDateFormat> threadSafeSdf =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
- 时区处理:通过setTimeZone方法控制
java sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
二、现代方案:DateTimeFormatter类
Java 8引入的java.time
包带来了全新的日期API。作为其中的格式化核心,DateTimeFormatter
具有不可变性和线程安全的先天优势。
基础用法示例:
java
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分");
String formatted = now.format(formatter); // 格式化
LocalDateTime parsed = LocalDateTime.parse("2023年08月20日 15时30分", formatter); // 解析
进阶特性:
1. 预定义格式:直接使用ISO标准格式
java
DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now());
本地化支持:自动适配地区格式
java DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) .withLocale(Locale.CHINA);
自定义解析器:处理非标准输入
java DateTimeFormatter lenientFormatter = new DateTimeFormatterBuilder() .appendPattern("yyyy-MM") .parseDefaulting(ChronoField.DAY_OF_MONTH, 1) .toFormatter();
三、关键差异对比
| 特性 | SimpleDateFormat | DateTimeFormatter |
|---------------------|------------------|-------------------|
| 线程安全 | 否 | 是 |
| 支持类型 | java.util.Date | java.time系列 |
| 时区处理 | 需手动设置 | 内置ZoneId |
| 性能表现 | 一般 | 更优 |
| 月份起始(1月) | 0-based | 1-based |
四、实战注意事项
时区陷阱:处理跨时区应用时,明确指定时区
java ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("America/New_York"));
闰秒处理:敏感场景需特别处理
java Instant instant = Instant.parse("2023-12-31T23:59:60Z");
性能优化:频繁使用的Formatter应缓存实例
java private static final DateTimeFormatter CACHED_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
异常处理:务必捕获ParseException/DateTimeParseException
五、迁移建议
对于新项目,强烈建议直接采用java.time
系列API。旧系统迁移时可以采用适配器模式:
java
public Date convert(LocalDateTime ldt) {
return Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
}