ZetCode

Java DateTimeFormatter 类

最后修改时间:2025 年 4 月 16 日

java.time.format.DateTimeFormatter 类提供了日期时间对象的格式化和解析功能。它是 Java 8 中引入的现代日期时间 API 的一部分。该类是线程安全且不可变的。

DateTimeFormatter 支持预定义的格式化器、基于模式的格式化以及本地化风格。它适用于所有时间类,如 LocalDate、LocalDateTime 和 ZonedDateTime。该类既处理将日期格式化为字符串,也处理将字符串解析为日期。

DateTimeFormatter 类概述

DateTimeFormatter 提供了常见格式的常量以及创建自定义模式的方法。关键特性包括区域敏感的格式化、类似于 SimpleDateFormat 的模式语法以及严格的解析规则。

public final class DateTimeFormatter {
    public static DateTimeFormatter ofPattern(String pattern);
    public static DateTimeFormatter ofPattern(String pattern, Locale locale);
    public static DateTimeFormatter ofLocalizedDate(FormatStyle dateStyle);
    public String format(TemporalAccessor temporal);
    public TemporalAccessor parse(CharSequence text);
    public TemporalAccessor parse(CharSequence text, ParsePosition position);
    public DateTimeFormatter withLocale(Locale locale);
    public DateTimeFormatter withResolverStyle(ResolverStyle resolverStyle);
}

上面的代码显示了 DateTimeFormatter 的关键方法。该类提供了灵活的格式化选项,同时保持了线程安全。它取代了旧的 SimpleDateFormat,后者存在线程安全问题。

使用预定义的格式化器

Java 提供了几个预定义的格式化器,用于常见的 ISO 和本地化格式。这些常量作为 DateTimeFormatter 中的静态字段提供。它们涵盖了大多数标准的日期时间表示。

Main.java
package com.zetcode;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {

    public static void main(String[] args) {
        
        LocalDateTime now = LocalDateTime.now();
        
        // ISO date time
        System.out.println("ISO_DATE_TIME: " + 
            now.format(DateTimeFormatter.ISO_DATE_TIME));
        
        // ISO date
        System.out.println("ISO_DATE: " + 
            now.format(DateTimeFormatter.ISO_DATE));
        
        // ISO time
        System.out.println("ISO_TIME: " + 
            now.format(DateTimeFormatter.ISO_TIME));
        
        // Basic ISO date (without separators)
        System.out.println("BASIC_ISO_DATE: " + 
            now.format(DateTimeFormatter.BASIC_ISO_DATE));
    }
}

此示例演示了如何使用预定义的 ISO 格式化器。输出显示了当前日期和时间的各种标准表示形式。这些格式化器在处理标准化的日期格式时非常有用。

使用自定义模式格式化

可以使用 ofPattern 方法创建自定义模式。模式语法使用字母来表示日期/时间组件。这些模式类似于 SimpleDateFormat 中使用的模式。

Main.java
package com.zetcode;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {

    public static void main(String[] args) {
        
        LocalDateTime now = LocalDateTime.now();
        
        // Custom pattern with date and time
        DateTimeFormatter formatter1 = DateTimeFormatter
            .ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println("Custom 1: " + now.format(formatter1));
        
        // Pattern with month name and day of week
        DateTimeFormatter formatter2 = DateTimeFormatter
            .ofPattern("EEEE, MMMM dd, yyyy");
        System.out.println("Custom 2: " + now.format(formatter2));
        
        // Pattern with 12-hour clock
        DateTimeFormatter formatter3 = DateTimeFormatter
            .ofPattern("hh:mm a");
        System.out.println("Custom 3: " + now.format(formatter3));
        
        // Pattern with time zone (for ZonedDateTime)
        DateTimeFormatter formatter4 = DateTimeFormatter
            .ofPattern("MM/dd/yyyy HH:mm z");
    }
}

此示例显示了各种自定义格式化模式。这些模式可以包含字面文本和特殊的模式字母。请注意,某些模式需要特定的时间类型(例如带有 ZonedDateTime 的时区)。

本地化格式化

DateTimeFormatter 通过 ofLocalized 方法和 withLocale 支持区域特定的格式化。这会生成适合不同语言和区域约定的输出。

Main.java
package com.zetcode;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;

public class Main {

    public static void main(String[] args) {
        
        LocalDateTime now = LocalDateTime.now();
        
        // Short format for current locale
        DateTimeFormatter shortFormatter = DateTimeFormatter
            .ofLocalizedDateTime(FormatStyle.SHORT);
        System.out.println("Short format: " + now.format(shortFormatter));
        
        // Medium format for French locale
        DateTimeFormatter mediumFrench = DateTimeFormatter
            .ofLocalizedDateTime(FormatStyle.MEDIUM)
            .withLocale(Locale.FRENCH);
        System.out.println("French medium: " + now.format(mediumFrench));
        
        // Full date with German locale
        DateTimeFormatter fullGerman = DateTimeFormatter
            .ofLocalizedDate(FormatStyle.FULL)
            .withLocale(Locale.GERMAN);
        System.out.println("German full date: " + now.format(fullGerman));
    }
}

此示例演示了区域敏感的格式化。输出根据指定的区域设置和格式样式而变化。FormatStyle 提供了 SHORT、MEDIUM、LONG 和 FULL 选项,用于不同的详细程度。

解析日期时间字符串

DateTimeFormatter 可以将字符串解析成日期时间对象。parse 方法将遵循格式化器模式的文本转换为时间对象。严格的解析确保了输入的有效性。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Main {

    public static void main(String[] args) {
        
        // Parse ISO date
        LocalDate date = LocalDate.parse("2025-12-31");
        System.out.println("Parsed date: " + date);
        
        // Parse with custom formatter
        DateTimeFormatter formatter = DateTimeFormatter
            .ofPattern("MM/dd/yyyy HH:mm");
        LocalDateTime dateTime = LocalDateTime.parse("12/25/2025 14:30", formatter);
        System.out.println("Parsed date-time: " + dateTime);
        
        // Parse with locale
        DateTimeFormatter frenchFormatter = DateTimeFormatter
            .ofPattern("d MMMM yyyy", java.util.Locale.FRENCH);
        LocalDate frenchDate = LocalDate.parse("25 décembre 2025", frenchFormatter);
        System.out.println("Parsed French date: " + frenchDate);
    }
}

此示例显示了将字符串解析成日期时间对象。默认情况下,解析器是严格的,会拒绝无效的日期。对于宽松的解析,请使用 withResolverStyle(ResolverStyle.LENIENT)

格式化 ZonedDateTime

在使用时区时,DateTimeFormatter 可以处理特定于时区的格式化。模式可以包含时区 ID 或偏移量。ZonedDateTime 提供了完整的时区感知日期时间信息。

Main.java
package com.zetcode;

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.ZoneId;

public class Main {

    public static void main(String[] args) {
        
        ZonedDateTime zonedNow = ZonedDateTime.now(ZoneId.of("America/New_York"));
        
        // Format with zone ID
        DateTimeFormatter formatter1 = DateTimeFormatter
            .ofPattern("yyyy-MM-dd HH:mm z");
        System.out.println("With zone: " + zonedNow.format(formatter1));
        
        // Format with zone offset
        DateTimeFormatter formatter2 = DateTimeFormatter
            .ofPattern("yyyy-MM-dd HH:mm XXX");
        System.out.println("With offset: " + zonedNow.format(formatter2));
        
        // Format with zone name
        DateTimeFormatter formatter3 = DateTimeFormatter
            .ofPattern("yyyy-MM-dd HH:mm VV");
        System.out.println("With zone name: " + zonedNow.format(formatter3));
    }
}

此示例演示了使用时区信息格式化 ZonedDateTime。不同的模式字母处理时区 ID、偏移量和名称。输出显示了同一时刻在不同时区表示中的情况。

组合格式化器

可以使用 withLocalewithResolverStyle 等方法组合或修改 DateTimeFormatter 实例。这允许从现有格式化器创建灵活的格式化器。

Main.java
package com.zetcode;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.format.ResolverStyle;
import java.util.Locale;

public class Main {

    public static void main(String[] args) {
        
        LocalDateTime now = LocalDateTime.now();
        
        // Create base formatter
        DateTimeFormatter base = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
        
        // Add locale
        DateTimeFormatter withLocale = base.withLocale(Locale.GERMAN);
        System.out.println("With German locale: " + now.format(withLocale));
        
        // Change to strict resolver
        DateTimeFormatter strict = base.withResolverStyle(ResolverStyle.STRICT);
        
        // Combine with localized time formatter
        DateTimeFormatter combined = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
            .withLocale(Locale.FRENCH);
        System.out.println("Combined French time: " + now.format(combined));
    }
}

此示例显示了如何修改和组合格式化器。解析器风格控制解析的宽松程度。组合格式化器可以混合基于模式的格式化和本地化格式化。

来源

Java DateTimeFormatter 类文档

在本文中,我们介绍了 Java DateTimeFormatter 类的基本方法和特性。掌握这些概念对于在 Java 应用程序中有效地处理日期时间至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在该领域拥有多年的经验。我从 2007 年开始撰写编程文章,至今已撰写了 1,400 多篇文章和 8 本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程