核心思想
无论使用哪种 API,将字符串转换为日期的核心步骤都是:
- 定义一个“格式”:告诉 Java 你的字符串长什么样("yyyy-MM-dd" 或 "MM/dd/yyyy HH:mm:ss")。
- 创建一个“解析器”:使用这个格式来创建一个可以解析字符串的对象。
- 执行“解析”操作:让解析器读取字符串,并把它转换成一个日期对象。
使用 java.time 包 (Java 8+,强烈推荐)
这是目前 Java 官方推荐的方式,它解决了旧 API 的诸多问题,如线程不安全、API 设计笨拙等。java.time 包下的类是不可变的,并且是线程安全的。
步骤:
- 使用
DateTimeFormatter来定义日期格式。 - 使用
LocalDate,LocalDateTime等类来接收解析后的结果。 - 如果你确实需要
java.util.Date对象(与旧代码交互),可以进行转换。
示例代码:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
public class StringToDateJava8 {
public static void main(String[] args) {
// --- 示例 1: 解析 "yyyy-MM-dd" 格式的字符串为 LocalDate ---
String dateString1 = "2025-10-27";
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate localDate = LocalDate.parse(dateString1, formatter1);
System.out.println("解析结果 (LocalDate): " + localDate);
System.out.println("年份: " + localDate.getYear());
System.out.println("月份: " + localDate.getMonthValue());
System.out.println("日期: " + localDate.getDayOfMonth());
System.out.println("------------------------------------");
// --- 示例 2: 解析 "yyyy/MM/dd HH:mm:ss" 格式的字符串为 LocalDateTime ---
String dateString2 = "2025/10/27 15:30:45";
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.parse(dateString2, formatter2);
System.out.println("解析结果 (LocalDateTime): " + localDateTime);
System.out.println("小时: " + localDateTime.getHour());
System.out.println("------------------------------------");
// --- 示例 3: 将 java.time.LocalDateTime 转换为 java.util.Date ---
// 这是常见的操作,用于与旧版 API 兼容
// 1. 将 LocalDateTime 转换为 Instant (时间戳)
// 2. 从 Instant 创建 java.util.Date
Date oldDate = Date.from(localDateTime.toInstant(java.time.ZoneOffset.UTC));
System.out.println("转换为旧版 Date: " + oldDate);
}
}
常用格式符号:
yyyy:四位年份MM:两位月份 (01-12)dd:两位日期 (01-31)HH:24小时制的小时 (00-23)hh:12小时制的小时 (01-12)mm:分钟 (00-59)ss:秒 (00-59)SSS:毫秒
使用 java.text.SimpleDateFormat (旧版,不推荐但仍在使用)
在 Java 8 之前,这是唯一的标准方法,但请注意,SimpleDateFormat 是非线程安全的,如果在多线程环境中共享同一个实例,会导致不可预期的错误,最佳实践是在每次使用时都创建一个新的实例。
示例代码:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDateOld {
public static void main(String[] args) {
String dateString = "2025-10-27 15:30:45";
// 定义格式,注意要和字符串的格式完全匹配
String formatPattern = "yyyy-MM-dd HH:mm:ss";
// 每次使用都创建新的实例,以保证线程安全
SimpleDateFormat sdf = new SimpleDateFormat(formatPattern);
try {
// 解析字符串
Date date = sdf.parse(dateString);
System.out.println("解析成功!");
System.out.println("Date 对象: " + date);
System.out.println("toString() 输出: " + date.toString()); // 输出符合 JVM 默认格式的日期
} catch (ParseException e) {
System.err.println("日期解析失败!请检查字符串格式是否匹配。");
e.printStackTrace();
}
}
}
关键点:
- 线程安全:绝对不要将
SimpleDateFormat声明为static成员变量在多线程中使用。 - 异常处理:
parse()方法会抛出ParseException,如果字符串格式与定义的formatPattern不匹配,必须进行捕获和处理。
使用 java.sql.Date (主要用于数据库)
java.sql.Date 是 java.util.Date 的一个子类,专门用于与 JDBC 交互,表示一个 yyyy-MM-dd 格式的日期(不包含时间部分)。
示例代码:
import java.sql.Date;
import java.text.SimpleDateFormat;
public class StringToSqlDate {
public static void main(String[] args) {
String dateString = "2025-10-27";
// java.sql.Date 的 valueOf 方法可以直接解析 "yyyy-MM-dd" 格式的字符串
// 这是最简单的方式,但格式是固定的
java.sql.Date sqlDate = java.sql.Date.valueOf(dateString);
System.out.println("使用 valueOf 解析: " + sqlDate);
// 也可以通过 java.util.Date 中转
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
java.util.Date utilDate = sdf.parse(dateString);
// java.sql.Date 构造方法需要一个 long 类型的时间戳
java.sql.Date sqlDate2 = new java.sql.Date(utilDate.getTime());
System.out.println("通过 utilDate 中转解析: " + sqlDate2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
关键点:
java.sql.Date.valueOf(String date)方法非常方便,但它只支持 "yyyy-MM-dd" 这一种格式。- 如果你的字符串格式不是这个,必须先用
SimpleDateFormat或java.time转成java.util.Date,再转成java.sql.Date。
总结与对比
| 特性 | java.time (Java 8+) |
SimpleDateFormat (旧版) |
java.sql.Date |
|---|---|---|---|
| 推荐度 | ⭐⭐⭐⭐⭐ 强烈推荐 | ⭐☆☆☆☆ 不推荐 | ⭐⭐☆☆☆ 仅限数据库 |
| 线程安全 | ✅ 是 (不可变对象) | ❌ 否 (每次需新建实例) | ✅ 是 (但其父类不是) |
| API 设计 | 现代、清晰、功能强大 | 陈旧、笨拙 | 功能单一 |
| 时区处理 | 完善 (ZonedDateTime, ZoneId) |
较弱 | 无 |
| 主要用途 | 新项目、所有日期时间业务 | 维护旧项目 | JDBC 操作数据库 |
| 核心类 | DateTimeFormatter, LocalDate, LocalDateTime |
SimpleDateFormat |
java.sql.Date |
最佳实践建议
- 新项目:绝对使用
java.time包,这是未来的方向,代码更健壮、更易读。 - 维护旧项目:如果项目代码中已经大量使用了
java.util.Date和SimpleDateFormat,可以继续使用,但要特别注意线程安全问题,避免将SimpleDateFormat设为static。 - 数据库交互:在 JDBC 中设置
PreparedStatement.setDate()时,使用java.sql.Date,但从你的业务逻辑层传递数据时,优先使用java.time.LocalDate,在准备 SQL 语句时再转换为java.sql.Date。
