杰瑞科技汇

Java String如何转Date?

我将从最现代、推荐的方式开始,然后介绍传统但仍在广泛使用的方式,并解释为什么现代方式更好。

Java String如何转Date?-图1
(图片来源网络,侵删)

核心概念:格式化器

无论使用哪种 API,核心思想都是:你不能随意地将一个字符串(如 "2025-10-27 15:30:00")转换成一个日期对象,你必须告诉 Java 你的字符串具体是什么格式,"年-月-日 时:分:秒"。

这个“翻译官”就是格式化器,在 Java 中:

  • DateTimeFormatter (Java 8+) 用于新的日期时间 API。
  • SimpleDateFormat (旧 API) 用于旧的 java.util.Datejava.util.Calendar

使用 Java 8+ 的 java.time API (强烈推荐)

这是目前 Java 世界中处理日期时间的标准方式,它设计更优秀,线程安全,并且功能更强大。

核心类

  • LocalDate: 表示一个日期(年-月-日),没有时间部分。
  • LocalTime: 表示一个时间(时-分-秒-纳秒),没有日期部分。
  • LocalDateTime: 表示一个日期和时间(年-月-日-时-分-秒-纳秒)。
  • DateTimeFormatter: 用于格式化和解析日期时间对象。
  • ZonedDateTime: 带有时区的日期时间。
  • Instant: 表示一个时间戳(自 1970-01-01T00:00:00Z 以来的秒/纳秒)。

示例代码

假设我们有字符串 "2025-10-27 15:30:00",想将其转换为 LocalDateTime

Java String如何转Date?-图2
(图片来源网络,侵删)
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public StringToDateExampleJava8 {
    public static void main(String[] args) {
        // 1. 定义你的字符串日期
        String dateString = "2025-10-27 15:30:00";
        // 2. 定义字符串的格式,必须与字符串的格式完全匹配!
        // yyyy: 年, MM: 月, dd: 日, HH: 24小时制, mm: 分, ss: 秒
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        try {
            // 3. 使用格式化器进行解析
            LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
            // 4. 输出结果
            System.out.println("原始字符串: " + dateString);
            System.out.println("转换后的 LocalDateTime: " + localDateTime);
            System.out.println("年份: " + localDateTime.getYear());
            System.out.println("月份: " + localDateTime.getMonthValue());
            System.out.println("小时: " + localDateTime.getHour());
            // --- 如果只需要日期部分 ---
            // 将 LocalDateTime 转换为 LocalDate
            LocalDate localDate = localDateTime.toLocalDate();
            System.out.println("转换后的 LocalDate: " + localDate);
            // --- 如果只需要时间部分 ---
            // 将 LocalDateTime 转换为 LocalTime
            LocalTime localTime = localDateTime.toLocalTime();
            System.out.println("转换后的 LocalTime: " + localTime);
        } catch (Exception e) {
            System.err.println("日期解析失败,请检查格式是否正确!");
            e.printStackTrace();
        }
    }
}

输出:

原始字符串: 2025-10-27 15:30:00
转换后的 LocalDateTime: 2025-10-27T15:30
年份: 2025
月份: 10
小时: 15
转换后的 LocalDate: 2025-10-27
转换后的 LocalTime: 15:30

常用格式模式

符号 含义 示例
yyyy 4位数年份 2025
MM 2位数月份 10
dd 2位数日期 27
HH 24小时制的小时 15
hh 12小时制的小时 03
mm 分钟 30
ss 00
SSS 毫秒 500
X 时区偏移 (e.g., +08, +0800, Z) +08:00

使用旧版 java.util.DateSimpleDateFormat

在 Java 8 之前,这是唯一的方式。最大的缺点是 SimpleDateFormat 是非线程安全的,在多线程环境下使用必须非常小心,否则会导致数据错误或程序异常。

核心类

  • java.util.Date: 表示一个特定的瞬间,精确到毫秒。
  • java.text.SimpleDateFormat: 用于格式化和解析 Date 对象。

示例代码

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public StringToDateExampleLegacy {
    public static void main(String[] args) {
        // 1. 定义你的字符串日期
        String dateString = "2025-10-27 15:30:00";
        // 2. 定义字符串的格式
        // 注意:SimpleDateFormat 是非线程安全的!不要在类级别声明它。
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            // 3. 使用格式化器进行解析
            Date date = formatter.parse(dateString);
            // 4. 输出结果
            System.out.println("原始字符串: " + dateString);
            System.out.println("转换后的 java.util.Date: " + date);
            // Date.toString() 的输出格式是英文的, Fri Oct 27 15:30:00 CST 2025
        } catch (ParseException e) {
            System.err.println("日期解析失败,请检查格式是否正确!");
            e.printStackTrace();
        }
    }
}

输出:

原始字符串: 2025-10-27 15:30:00
转换后的 java.util.Date: Fri Oct 27 15:30:00 CST 2025

SimpleDateFormat 的线程安全问题

SimpleDateFormat 内部持有一个可变的 Calendar 实例,当多个线程同时调用其 parse()format() 方法时,会竞争同一个 Calendar 实例,导致解析错误。

错误的做法 (在多线程环境下):

// 错误!不要在多线程环境下共享同一个 SimpleDateFormat 实例。
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public void parse(String dateStr) {
    try {
        sdf.parse(dateStr);
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

正确的做法 (在多线程环境下):

  1. 每次创建新实例 (不推荐,性能差):

    // 每次调用都创建一个新的,开销大
    new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
  2. 使用 ThreadLocal (推荐的做法):

    private static final ThreadLocal<SimpleDateFormat> threadLocalSdf = 
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
    public void parse(String dateStr) {
        try {
            // 从当前线程的局部变量中获取
            threadLocalSdf.get().parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

总结与对比

特性 Java 8+ java.time API 旧版 java.util.Date API
核心类 LocalDate, LocalDateTime, DateTimeFormatter Date, SimpleDateFormat
线程安全 DateTimeFormatter 是不可变的,天生线程安全。 SimpleDateFormat 是可变的,非线程安全。
API 设计 清晰、易用date.getYear()date.getYear() + 1900 直观得多。 笨拙、不直观,很多方法已经过时,且月份从0开始。
功能 更强大,支持时区、持续时间、日期计算等现代功能。 功能有限,时区处理等操作非常复杂。
推荐度 强烈推荐,所有新项目都应使用此 API。 不推荐,仅用于维护旧代码或与旧系统交互。

如何选择?

  • 新项目: 毫不犹豫地使用 Java 8+ 的 java.time API,它更安全、更强大、更符合现代编程思想。
  • 维护旧代码: 如果项目代码库已经大量使用了 java.util.DateSimpleDateFormat,为了保持一致性,可以继续使用,但必须注意其线程安全问题(推荐使用 ThreadLocal)。
  • 混合使用: 如果新代码需要和旧代码交互,java.time API 提供了转换方法。java.util.Date 可以转换为 Instant,而 Instant 又可以转换为 java.time 中的对象。
    // java.util.Date -> java.time.Instant -> java.time.LocalDateTime
    Date oldDate = new Date();
    Instant instant = oldDate.toInstant();
    LocalDateTime ldt = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
分享:
扫描分享到社交APP
上一篇
下一篇