将字符串转换为 java.util.Date
对象是 Java 开发中的常见需求。由于 Date
本身不包含格式信息,它只是一个时间戳(自 1970-01-01 00:00:00 UTC 起的毫秒数),因此需要借助 格式化工具 来解析字符串。
关键类
类名 | 包路径 | 说明 |
---|---|---|
SimpleDateFormat |
java.text.* |
传统方式,线程不安全,功能强大 |
DateTimeFormatter |
java.time.format.* |
Java 8+ 推荐,线程安全,类型安全 |
Date |
java.util.* |
存储时间点(已过时部分方法) |
LocalDateTime , ZonedDateTime |
java.time.* |
新时间 API,推荐使用 |
✅ 现代建议:优先使用
java.time
包 +DateTimeFormatter
操作步骤(非常详细)
方法一:使用 SimpleDateFormat
(传统方式)
步骤 1:导入必要的类
import java.text.SimpleDateFormat;
import java.util.Date;
步骤 2:定义日期格式模式
String pattern = "yyyy-MM-dd HH:mm:ss";
// 常见模式符号:
// yyyy - 四位年份
// MM - 两位月份(01-12)
// dd - 两位日期(01-31)
// HH - 24小时制小时(00-23)
// mm - 分钟(00-59)
// ss - 秒(00-59)
步骤 3:创建 SimpleDateFormat
实例
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
步骤 4:调用 parse()
方法转换
String dateString = "2025-08-15 10:30:45";
try {
Date date = sdf.parse(dateString); // 转换成功返回 Date 对象
System.out.println("转换结果: " + date);
} catch (ParseException e) {
System.err.println("解析失败: " + e.getMessage());
}
完整示例
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDate_SimpleDateFormat {
public static void main(String[] args) {
String input = "2025-08-15 10:30:45";
String pattern = "yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
try {
Date date = sdf.parse(input);
System.out.println("原始字符串: " + input);
System.out.println("转换后的Date: " + date);
} catch (ParseException e) {
System.err.println("格式错误,无法解析: " + e.getMessage());
}
}
}
方法二:使用 java.time
API(推荐,Java 8+)
步骤 1:导入新时间 API 类
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
步骤 2:定义格式化器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
步骤 3:解析为 LocalDateTime
String dateString = "2025-08-15 10:30:45";
LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter);
步骤 4:如需 java.util.Date
,进行转换
import java.util.Date;
import java.time.ZoneId;
// LocalDateTime 转 Date
Date date = Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant());
完整示例
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.ZoneId;
import java.util.Date;
public class StringToDate_Modern {
public static void main(String[] args) {
String input = "2025-08-15 10:30:45";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
try {
LocalDateTime ldt = LocalDateTime.parse(input, formatter);
Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
System.out.println("LocalDateTime: " + ldt);
System.out.println("转换为 Date: " + date);
} catch (Exception e) {
System.err.println("解析异常: " + e.getMessage());
}
}
}
常见错误
错误类型 | 示例 | 原因 | 修复方法 |
---|---|---|---|
ParseException |
"2025/08/15" 用 "yyyy-MM-dd" 解析 |
格式不匹配(斜杠 vs 连字符) | 修改格式或字符串 |
NullPointerException |
sdf.parse(null) |
输入为 null | 提前判空 |
IllegalArgumentException |
ofPattern("HH:MM:ss") |
MM 错误(应为 mm 表示分钟) | 使用正确模式:mm |
时区混乱 | UTC 字符串转本地时间出错 | 未指定时区 | 使用 ZonedDateTime 或明确设置时区 |
线程安全问题 | 多线程共用一个 SimpleDateFormat |
SimpleDateFormat 非线程安全 |
使用 ThreadLocal 或改用 DateTimeFormatter |
注意事项
- ⚠️
SimpleDateFormat
非线程安全:不要在多线程环境中共享同一个实例。 - ⚠️ 模式大小写敏感:
MM
= 月份mm
= 分钟SS
= 毫秒(大写 S)ss
= 秒
- ⚠️ 闰年、时区、夏令时:复杂日期需考虑这些因素,建议使用
ZonedDateTime
。 - ⚠️ 默认时区:
Date.toString()
使用本地时区显示,但内部时间是 UTC。 - ⚠️ 异常必须处理:
parse()
方法抛出ParseException
,必须try-catch
。
使用技巧
技巧 1:预定义常用格式
public class DateFormats {
public static final DateTimeFormatter YYYY_MM_DD_HHMMSS =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static final DateTimeFormatter ISO_DATE =
DateTimeFormatter.ISO_DATE;
}
技巧 2:支持多种格式尝试解析
public static Date parseFlexible(String dateStr) throws ParseException {
String[] patterns = {"yyyy-MM-dd", "dd/MM/yyyy", "yyyy年MM月dd日"};
for (String pattern : patterns) {
try {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return sdf.parse(dateStr);
} catch (ParseException e) {
continue;
}
}
throw new ParseException("所有格式均不匹配", 0);
}
技巧 3:使用 Optional
避免异常
public static Optional<Date> safeParse(String str, String pattern) {
try {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
return Optional.of(sdf.parse(str));
} catch (ParseException e) {
return Optional.empty();
}
}
最佳实践与性能优化
✅ 最佳实践
实践 | 说明 |
---|---|
✅ 优先使用 java.time |
更清晰、安全、功能强大 |
✅ 使用 DateTimeFormatter 常量 |
避免重复创建,线程安全 |
✅ 封装解析逻辑 | 提供统一接口,降低耦合 |
✅ 明确指定时区 | 避免默认时区带来的歧义 |
✅ 输入校验 | 判空、长度检查等 |
⚙️ 性能优化
缓存
SimpleDateFormat
实例(若必须使用):private static final ThreadLocal<SimpleDateFormat> SDF_THREADLOCAL = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
重用
DateTimeFormatter
:它是不可变且线程安全的,可定义为static final
。避免频繁创建对象:在循环中不要每次都
new SimpleDateFormat()
。使用
Instant
直接解析 ISO 格式:Instant instant = Instant.parse("2025-08-15T10:30:45Z"); // 高效
批量处理时预编译格式:尤其在数据导入场景。
总结
维度 | 说明 |
---|---|
核心工具 | SimpleDateFormat (旧)、DateTimeFormatter (新) |
关键步骤 | 定义格式 → 创建格式化器 → 调用 parse() → 处理异常 |
常见陷阱 | 格式不匹配、大小写错误、线程安全、时区问题 |
现代推荐 | LocalDateTime.parse(str, formatter) |
性能要点 | 缓存格式化器、避免重复创建、使用 Instant 解析标准格式 |
最佳选择 | Java 8+ 项目一律使用 java.time API |
✅ 一句话总结:字符串转
Date
的核心是格式匹配,推荐使用java.time.LocalDateTime
+DateTimeFormatter
,避免SimpleDateFormat
的线程安全问题,封装解析逻辑以提高代码健壮性。