杰瑞科技汇

java中string转date

核心概念

  1. java.util.Date:Java 最早、最基础的日期时间类,它代表了一个特定的瞬间,精确到毫秒。注意:它不包含时区信息,并且很多方法(如 getYear(), getMonth())已经过时(@Deprecated),不推荐在新代码中使用。
  2. java.text.SimpleDateFormat:一个不线程安全的类,用于日期和时间的格式化和解析,这是将 StringDate 互转最传统的方式。
  3. java.time 包 (Java 8+):Java 8 引入的一全新的、不可变且线程安全的日期时间 API,这是目前强烈推荐使用的现代方式,它包含 LocalDate, LocalDateTime, ZonedDateTime 等类,以及 DateTimeFormatter 用于格式化。

使用旧 API (java.util.DateSimpleDateFormat)

这种方式在旧代码中非常普遍,但由于 SimpleDateFormat 的线程安全问题,使用时需要特别小心。

java中string转date-图1
(图片来源网络,侵删)

基本转换

这是最直接的转换方式。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDateOld {
    public static void main(String[] args) {
        // 1. 定义日期字符串和格式
        String dateString = "2025-10-27 10:30:00";
        String pattern = "yyyy-MM-dd HH:mm:ss";
        // 2. 创建 SimpleDateFormat 对象
        // !!! 重要:SimpleDateFormat 不是线程安全的,不要在多线程环境下共享同一个实例 !!!
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        try {
            // 3. 解析字符串为 Date 对象
            Date date = sdf.parse(dateString);
            // 4. 验证结果
            System.out.println("原始字符串: " + dateString);
            System.out.println("转换后的 Date 对象: " + date); // Date 对象的 toString() 会输出其内部表示
            System.out.println("格式化后的 Date: " + sdf.format(date)); // 用同一个格式化器再格式化回来,验证正确性
        } catch (ParseException e) {
            System.err.println("日期解析失败,请检查格式是否匹配!");
            e.printStackTrace();
        }
    }
}

常见日期格式示例

SimpleDateFormat 的模式字母非常关键:

字母 含义 示例
y yyyy (2025), yy (23)
M MM (10), MMM (Oct), MMMM (October)
d dd (27)
H 小时 (24小时制) HH (10)
h 小时 (12小时制) hh (10)
m 分钟 mm (30)
s ss (00)
S 毫秒 SSS (123)

示例:解析不同格式的字符串

String dateStr1 = "2025/10/27";
String pattern1 = "yyyy/MM/dd";
String dateStr2 = "27-Oct-2025";
String pattern2 = "dd-MMM-yyyy";
// ... 使用 sdf.parse() 进行解析 ...

线程安全问题 (非常重要)

SimpleDateFormat 的内部状态在解析和格式化过程中会发生变化,如果在多线程环境下共享同一个 SimpleDateFormat 实例,会导致解析结果错误或 NullPointerException

java中string转date-图2
(图片来源网络,侵删)

错误示范 (多线程环境)

// 不要这样做!
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public void parseInMultiThread(String dateStr) {
    new Thread(() -> {
        try {
            System.out.println(Thread.currentThread().getName() + ": " + sdf.parse(dateStr));
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }).start();
}

解决方案 1:每次创建新实例 (性能差)

// 在方法内部创建,虽然安全,但频繁创建销毁对象会影响性能
public Date parse(String dateStr) throws ParseException {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    return sdf.parse(dateStr);
}

解决方案 2:使用 synchronized 同步块 (性能较差)

private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public synchronized Date parse(String dateStr) throws ParseException {
    return sdf.parse(dateStr);
}

使用现代 API (Java 8+ java.time)

这是目前 最佳实践java.time API 设计优秀,解决了旧 API 的所有痛点:线程安全、易用、功能强大。

java中string转date-图3
(图片来源网络,侵删)

基本转换

java.time 提供了多个类来处理不同场景的日期时间,你需要根据你的字符串内容选择合适的类。

  • LocalDate: 仅包含日期 (年月日),如 2025-10-27
  • LocalTime: 仅包含时间 (时分秒),如 10:30:00
  • LocalDateTime: 包含日期和时间,但不带时区,如 2025-10-27T10:30:00
  • ZonedDateTime: 包含日期、时间和时区,如 2025-10-27T10:30:00+08:00[Asia/Shanghai]

示例:LocalDateTime 转换

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class StringToDateModern {
    public static void main(String[] args) {
        // 1. 定义日期字符串和格式
        String dateString = "2025-10-27 10:30:00";
        String pattern = "yyyy-MM-dd HH:mm:ss";
        // 2. 创建 DateTimeFormatter 对象
        // DateTimeFormatter 是线程安全的,可以安全地定义为 static final 常量
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
        try {
            // 3. 解析字符串为 LocalDateTime 对象
            LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter);
            // 4. 验证结果
            System.out.println("原始字符串: " + dateString);
            System.out.println("转换后的 LocalDateTime 对象: " + dateTime);
            System.out.println("格式化后的 LocalDateTime: " + dateTime.format(formatter));
            // 如果你需要 java.util.Date 对象(与旧系统交互)
            // 可以先转换为 Instant,再转换为 Date
            java.util.Date date = java.util.Date.from(dateTime.atZone(java.time.ZoneId.systemDefault()).toInstant());
            System.out.println("转换回 java.util.Date: " + date);
        } catch (Exception e) {
            System.err.println("日期解析失败,请检查格式是否匹配!");
            e.printStackTrace();
        }
    }
}

解析为 java.util.Date 的现代方式

如果你必须得到一个 java.util.Date 对象,推荐通过 Instant 中转,这是最清晰和可靠的方式。

import java.time.*;
import java.time.format.DateTimeFormatter;
public class StringToUtilDateModern {
    public static void main(String[] args) {
        String dateString = "2025-10-27 10:30:00";
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 1. 解析为 LocalDateTime
        LocalDateTime localDateTime = LocalDateTime.parse(dateString, formatter);
        // 2. 获取系统默认时区
        ZoneId zoneId = ZoneId.systemDefault();
        // 3. 将 LocalDateTime 转换为 ZonedDateTime (加上时区信息)
        ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
        // 4. 将 ZonedDateTime 转换为 Instant (时间线上的一个瞬时点)
        Instant instant = zonedDateTime.toInstant();
        // 5. 将 Instant 转换为 java.util.Date
        java.util.Date date = java.util.Date.from(instant);
        System.out.println("最终得到的 java.util.Date: " + date);
    }
}

总结与最佳实践

特性 java.util.Date + SimpleDateFormat java.time API
推荐度 ⭐⭐ (仅维护旧代码时使用) ⭐⭐⭐⭐⭐ (新项目首选)
线程安全 ❌ 不安全,需额外处理 ✅ 安全,DateTimeFormatter 是线程安全的
API 设计 繁琐,方法大多已过时 现代化,清晰易用 (如 LocalDate, LocalDateTime)
时区处理 支持,但容易出错 强大且直观 (ZonedDateTime, ZoneId)
不可变性 可变 不可变,更安全
性能 一般 通常更好
  1. 新项目:请务必使用 java.time API,它是 Java 日期时间的未来,能让你避免很多潜在的 bug。
  2. 维护旧项目:如果你必须使用 java.util.Date,请务必注意 SimpleDateFormat 的线程安全问题,最好的做法是在解析时创建新的实例,或者使用 synchronized 块(但性能有损耗)。
  3. 与旧代码交互:当你使用 java.time 解析完数据后,如果某个旧库需要 java.util.Date,请通过 Instant 进行转换,这是最标准的方式。
分享:
扫描分享到社交APP
上一篇
下一篇