杰瑞科技汇

Java DateTime 如何自定义格式?

Java 日期时间的格式化主要涉及两个核心类:

Java DateTime 如何自定义格式?-图1
(图片来源网络,侵删)
  1. java.text.SimpleDateFormat: 传统的、功能强大的格式化类,但存在线程不安全的问题。
  2. java.time.format.DateTimeFormatter: Java 8 引入的新日期时间 API 的一部分,是线程安全的,也是目前推荐使用的方式。

下面我们分别详细介绍这两个类,并提供最常用的格式化模式。


传统方式:SimpleDateFormat (不推荐在新代码中使用)

SimpleDateFormat 是一个非常灵活的类,可以通过模式字符串来定义日期时间的格式。

核心方法

  • format(Date date): 将 Date 对象格式化为字符串。
  • parse(String source): 将字符串解析为 Date 对象。

格式化模式

模式字符是定义格式的关键,以下是一些最常用的模式字符:

字母 含义 示例
y yyyy (2025), yy (23)
M MM (05), M (5)
d 月中的天 dd (09), d (9)
H 小时 (24小时制) HH (14), H (14)
h 小时 (12小时制) hh (02), h (2)
m 分钟 mm (05), m (5)
s ss (09), s (9)
S 毫秒 SSS (009)
E 星期几 EEE (Tue), EEEE (Tuesday)
a 上午/下午标记 AM, PM
z 时区 Asia/Shanghai, GMT+08:00

代码示例

import java.text.SimpleDateFormat;
import java.util.Date;
public class SimpleDateFormatExample {
    public static void main(String[] args) {
        // 1. 创建一个格式化器
        // 格式: 年-月-日 时:分:秒 星期几
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EEEE");
        // 2. 获取当前时间
        Date now = new Date();
        // 3. 格式化日期为字符串
        String formattedDate = sdf.format(now);
        System.out.println("格式化后的日期: " + formattedDate);
        // 输出可能类似于: 格式化后的日期: 2025-10-27 15:30:45 Friday
        // 4. 解析字符串为日期对象
        String dateStr = "2025-12-25 10:00:00";
        try {
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date parsedDate = sdf2.parse(dateStr);
            System.out.println("解析后的日期对象: " + parsedDate);
            // 输出类似于: 解析后的日期对象: Mon Dec 25 10:00:00 CST 2025
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

⚠️ 重要警告:线程不安全

SimpleDateFormat 不是线程安全的,如果在多线程环境下共享同一个 SimpleDateFormat 实例,可能会导致数据错乱或程序异常。

Java DateTime 如何自定义格式?-图2
(图片来源网络,侵删)

错误示范 (多线程环境下):

// 不要这样做!
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
    executor.submit(() -> {
        try {
            System.out.println(sdf.format(new Date()));
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    });
}

解决方案 (如果必须使用):

  1. 每次创建新实例: 在方法内部 new SimpleDateFormat(),性能开销大。
  2. 使用 ThreadLocal: 为每个线程创建一个独立的实例,这是常见的解决方案。
private static final ThreadLocal<SimpleDateFormat> threadLocalSDF =
    ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
// 使用时
String dateStr = threadLocalSDF.get().format(new Date());

现代方式:DateTimeFormatter (推荐)

Java 8 引入了全新的 java.time 包,解决了旧 API 的所有痛点,DateTimeFormatter 就是其中用于格式化的类,它是线程安全的

核心类关系

  • LocalDate: 表示一个日期 (年-月-日),如 2025-10-27
  • LocalTime: 表示一个时间 (时-分-秒-纳秒),如 15:30:45
  • LocalDateTime: 表示一个日期和时间 (年-月-日-时-分-秒),如 2025-10-27T15:30:45
  • DateTimeFormatter: 负责格式化和解析上述对象。

格式化模式

DateTimeFormatter 的模式字符与 SimpleDateFormat 基本兼容,但更规范。

Java DateTime 如何自定义格式?-图3
(图片来源网络,侵删)
字母 含义 示例
y yyyy (2025), yy (23)
M MM (05), M (5)
d 月中的天 dd (09), d (9)
H 小时 (24小时制) HH (14), H (14)
h 小时 (12小时制) hh (02), h (2)
m 分钟 mm (05), m (5)
s ss (09), s (9)
S 纳秒 SSSSSSSSS (000000009)
n 纳秒 (更常用) n (9), nnnnnnnnn (000000009)
E 星期几 EEE (Tue), EEEE (Tuesday)
a 上午/下午标记 AM, PM
Z 时区偏移 Z (UTC), GMT+8
V 时区ID Asia/Shanghai

代码示例

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class DateTimeFormatterExample {
    public static void main(String[] args) {
        // 1. 创建一个格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss EEEE");
        // 2. 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        // 3. 格式化日期时间为字符串
        String formattedDateTime = now.format(formatter);
        System.out.println("格式化后的日期时间: " + formattedDateTime);
        // 输出可能类似于: 格式化后的日期时间: 2025-10-27 15:30:45 Friday
        // 4. 解析字符串为日期时间对象
        String dateTimeStr = "2025-12-25 10:00:00";
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeStr, formatter2);
        System.out.println("解析后的日期时间对象: " + parsedDateTime);
        // 输出: 解析后的日期时间对象: 2025-12-25T10:00:00
        // 5. 使用预定义的格式化器
        DateTimeFormatter isoFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        System.out.println("ISO格式: " + now.format(isoFormatter)); // 输出: 2025-10-27T15:30:45.123
    }
}

常用格式化模式速查表

格式字符串 描述 示例
yyyy-MM-dd 标准日期格式 2025-10-27
yyyyMMdd 紧凑日期格式 20251027
dd/MM/yyyy 欧洲风格日期 27/10/2025
MM/dd/yyyy 美国风格日期 10/27/2025
HH:mm:ss 24小时制时间 15:30:45
hh:mm:ss a 12小时制时间 03:30:45 PM
yyyy-MM-dd HH:mm:ss 完整日期时间 (常用) 2025-10-27 15:30:45
yyyy-MM-dd'T'HH:mm:ss ISO 8601 标准格式 2025-10-27T15:30:45
yyyy-MM-dd'T'HH:mm:ss.SSS 带毫秒的ISO 8601格式 2025-10-27T15:30:45.123
yyyy-MM-dd'T'HH:mm:ss.SSSZ 带时区偏移的ISO 8601格式 2025-10-27T15:30:45.123+0800
EEE, d MMM yyyy RFC 1123 格式 (如邮件头) Fri, 27 Oct 2025
yyyyMMddHHmmss 紧凑日期时间 (日志文件名常用) 20251027153045

总结与最佳实践

特性 SimpleDateFormat (旧) DateTimeFormatter (新)
线程安全 ❌ 不安全 ✅ 安全
API 设计 基于 java.util.Date,设计有缺陷 基于 java.time,类型更明确 (LocalDate, LocalTime 等)
时区处理 复杂,容易出错 清晰,有专门的 ZonedDateTime, OffsetDateTime
闰秒等 无法处理 正确处理
推荐度 仅用于维护旧代码 强烈推荐用于所有新项目

核心建议:

  1. 新项目必须使用 java.time API,即 LocalDateTime, ZonedDateTime 配合 DateTimeFormatter

  2. 如果必须维护旧的 java.util.Date 代码,可以通过 Date.from(localDateTime.toInstant())Date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime() 进行转换。

  3. DateTimeFormatter 定义为 static final 常量,因为它可以被安全地共享,提高性能。

    public class DateFormatter {
        private static final DateTimeFormatter DATE_FORMATTER = 
            DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        public static String format(LocalDate date) {
            return date.format(DATE_FORMATTER);
        }
    }
分享:
扫描分享到社交APP
上一篇
下一篇