ZetCode

Java DateTimeFormatterBuilder 类

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

java.time.format.DateTimeFormatterBuilder 类提供了一种灵活的方式来创建自定义日期和时间格式化程序。它允许精确控制格式化模式、文本样式和可选部分。

当预定义的格式化程序不满足需求时,可以使用 DateTimeFormatterBuilder。它支持区域设置敏感的格式化、填充和附加文字。构建器模式支持逐步构建格式化程序。

DateTimeFormatterBuilder 概述

构建器类提供了附加各种日期/时间组件的方法。它可以组合模式、文本样式和文字值。最终的格式化程序通过调用 toFormatter() 创建。

public final class DateTimeFormatterBuilder {
    public DateTimeFormatterBuilder appendPattern(String pattern);
    public DateTimeFormatterBuilder appendValue(TemporalField field);
    public DateTimeFormatterBuilder appendText(TemporalField field, TextStyle style);
    public DateTimeFormatterBuilder appendLiteral(String literal);
    public DateTimeFormatterBuilder appendFraction(TemporalField field, 
        int minWidth, int maxWidth, boolean decimalPoint);
    public DateTimeFormatterBuilder optionalStart();
    public DateTimeFormatterBuilder optionalEnd();
    public DateTimeFormatter toFormatter();
}

该代码展示了 DateTimeFormatterBuilder 的关键方法。这些方法允许从简单的组件构建复杂的格式化程序。构建器可以处理日期/时间字段的数字和文本表示形式。

基本格式化程序构建

此示例演示了使用构建器创建简单格式化程序。我们将组合不同的日期组件和文字文本来创建自定义格式。格式化程序将以“日、月 年”格式显示日期。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendText(java.time.temporal.ChronoField.DAY_OF_WEEK, TextStyle.FULL)
            .appendLiteral(", ")
            .appendText(java.time.temporal.ChronoField.MONTH_OF_YEAR, TextStyle.FULL)
            .appendLiteral(' ')
            .appendValue(java.time.temporal.ChronoField.YEAR)
            .toFormatter();
            
        LocalDate date = LocalDate.of(2025, 4, 16);
        String formatted = date.format(formatter);
        
        System.out.println("Formatted date: " + formatted);
    }
}

此代码创建一个格式化程序,生成类似“Wednesday, April 2025”的输出。构建器附加了日期和月份的完整文本,以及文字逗号和空格。年份作为数值附加。

基于模式的格式化

构建器可以包含类似于 SimpleDateFormat 的模式字符串。此示例展示了如何将基于模式的格式化与构建器方法相结合。我们将创建一个带有可选毫秒的格式。

Main.java
package com.zetcode;

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

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendPattern("yyyy-MM-dd HH:mm:ss")
            .optionalStart()
            .appendLiteral('.')
            .appendFraction(java.time.temporal.ChronoField.MILLI_OF_SECOND, 3, 3, false)
            .optionalEnd()
            .toFormatter();
            
        LocalDateTime dateTime1 = LocalDateTime.of(2025, 4, 16, 14, 30, 45);
        LocalDateTime dateTime2 = LocalDateTime.of(2025, 4, 16, 14, 30, 45, 500_000_000);
        
        System.out.println("Without milliseconds: " + dateTime1.format(formatter));
        System.out.println("With milliseconds: " + dateTime2.format(formatter));
    }
}

此格式化程序处理带有和不带有毫秒的时间戳。optionalStart()optionalEnd() 方法使毫秒部分成为可选的。小数部分格式化为精确的 3 位数字。

区域设置敏感的格式化

此示例演示了创建特定于区域设置的格式化程序。我们将构建一个格式化程序,根据指定的区域设置显示月份名称。相同的格式化程序将为不同的区域设置生成不同的输出。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.util.Locale;

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendValue(java.time.temporal.ChronoField.DAY_OF_MONTH)
            .appendLiteral(' ')
            .appendText(java.time.temporal.ChronoField.MONTH_OF_YEAR, TextStyle.FULL)
            .appendLiteral(' ')
            .appendValue(java.time.temporal.ChronoField.YEAR)
            .toFormatter();
            
        LocalDate date = LocalDate.of(2025, 4, 16);
        
        System.out.println("US format: " + 
            date.format(formatter.withLocale(Locale.US)));
        System.out.println("French format: " + 
            date.format(formatter.withLocale(Locale.FRENCH)));
        System.out.println("Japanese format: " + 
            date.format(formatter.withLocale(Locale.JAPANESE)));
    }
}

输出将显示不同语言的月份名称。对于美国区域设置,它是“16 April 2025”,对于法语是“16 avril 2025”,对于日语是“16 4月 2025”。格式化程序自动适应指定的区域设置。

填充和对齐

构建器允许精确控制字段填充和对齐。此示例展示了如何创建带有填充的固定宽度数字字段。我们将使用填充到 2 位数字的时和分来格式化时间。

Main.java
package com.zetcode;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendValue(java.time.temporal.ChronoField.HOUR_OF_DAY, 2)
            .appendLiteral(':')
            .appendValue(java.time.temporal.ChronoField.MINUTE_OF_HOUR, 2)
            .toFormatter();
            
        LocalTime time1 = LocalTime.of(9, 5);
        LocalTime time2 = LocalTime.of(14, 30);
        
        System.out.println("Time 1: " + time1.format(formatter));
        System.out.println("Time 2: " + time2.format(formatter));
    }
}

输出将显示诸如“09:05”和“14:30”的时间,具有一致的 2 位数字格式。appendValue 的第二个参数指定最小字段宽度,并根据需要添加填充。

复合格式化程序

此示例演示了将多个格式化程序组合成一个。我们将创建单独的日期和时间格式化程序,然后使用文字分隔符将它们组合在一起。这种方法提高了格式化程序组件的可重用性。

Main.java
package com.zetcode;

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

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder()
            .appendPattern("MMM dd, yyyy")
            .toFormatter();
            
        DateTimeFormatter timeFormatter = new DateTimeFormatterBuilder()
            .appendPattern("hh:mm a")
            .toFormatter();
            
        DateTimeFormatter combinedFormatter = new DateTimeFormatterBuilder()
            .append(dateFormatter)
            .appendLiteral(" at ")
            .append(timeFormatter)
            .toFormatter();
            
        LocalDateTime dateTime = LocalDateTime.of(2025, 4, 16, 14, 30);
        System.out.println("Combined format: " + dateTime.format(combinedFormatter));
    }
}

输出格式将类似于“Apr 16, 2025 at 02:30 PM”。该示例展示了如何从更简单的组件构建复杂的格式化程序。每个子格式化程序可以独立使用或与其他格式化程序组合使用。

处理不同的日历

此高级示例展示了如何为非 ISO 日历创建格式化程序。我们将为日本帝国日历系统构建一个格式化程序。该格式化程序将显示带有日本年号名称的日期。

Main.java
package com.zetcode;

import java.time.LocalDate;
import java.time.chrono.JapaneseDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.TextStyle;
import java.util.Locale;

public class Main {

    public static void main(String[] args) {
        
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
            .appendText(java.time.temporal.ChronoField.ERA, TextStyle.FULL)
            .appendLiteral(' ')
            .appendValue(java.time.temporal.ChronoField.YEAR_OF_ERA)
            .appendLiteral('年 ')
            .appendText(java.time.temporal.ChronoField.MONTH_OF_YEAR, TextStyle.FULL)
            .appendLiteral(' ')
            .appendValue(java.time.temporal.ChronoField.DAY_OF_MONTH)
            .appendLiteral('日')
            .toFormatter()
            .withLocale(Locale.JAPANESE);
            
        JapaneseDate japaneseDate = JapaneseDate.from(LocalDate.of(2025, 4, 16));
        System.out.println("Japanese date: " + japaneseDate.format(formatter));
    }
}

输出将以带有年号名称的日语格式显示日期。对于 2025 年,这将是“令和 7年 4月 16日”。格式化程序正确处理日本日历系统,包括正确的年号命名和组件排序。

来源

Java DateTimeFormatterBuilder 文档

本教程介绍了 DateTimeFormatterBuilder 的基本功能。借助这些技术,您可以创建定制的复杂日期/时间格式化程序,以满足您的特定要求。构建器模式提供了超越标准格式化模式的灵活性。

作者

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

列出所有Java教程