Java DateTimeFormatterBuilder Class
Last modified: April 16, 2025
The java.time.format.DateTimeFormatterBuilder
class provides a
flexible way to create custom date and time formatters. It allows precise
control over formatting patterns, text styles, and optional sections.
DateTimeFormatterBuilder
is used when predefined formatters don't
meet requirements. It supports locale-sensitive formatting, padding, and
appending of literals. The builder pattern enables step-by-step formatter
construction.
DateTimeFormatterBuilder Overview
The builder class provides methods to append various date/time components.
It can combine patterns, text styles, and literal values. The final formatter
is created by calling 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(); }
The code shows key methods of DateTimeFormatterBuilder
. These allow
building complex formatters from simple components. The builder can handle both
numeric and text representations of date/time fields.
Basic Formatter Construction
This example demonstrates creating a simple formatter using the builder. We'll combine different date components with literal text to create a custom format. The formatter will display date in "Day, Month Year" format.
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); } }
This code creates a formatter that produces output like "Wednesday, April 2025". The builder appends full text for day and month, with literal commas and spaces. The year is appended as a numeric value.
Pattern-Based Formatting
The builder can incorporate pattern strings similar to SimpleDateFormat. This example shows how to combine pattern-based formatting with builder methods. We'll create a format with optional milliseconds.
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)); } }
This formatter handles both timestamps with and without milliseconds. The
optionalStart()
and optionalEnd()
methods make the
milliseconds section optional. The fraction is formatted with exactly 3 digits.
Locale-Sensitive Formatting
This example demonstrates creating locale-specific formatters. We'll build a formatter that displays month names according to the specified locale. The same formatter will produce different output for different locales.
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))); } }
The output will show month names in different languages. For US locale it's "16 April 2025", for French "16 avril 2025", and for Japanese "16 4月 2025". The formatter automatically adapts to the specified locale.
Padding and Alignment
The builder allows precise control over field padding and alignment. This example shows how to create fixed-width numeric fields with padding. We'll format a time with hours and minutes padded to 2 digits.
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)); } }
The output will show times as "09:05" and "14:30" with consistent 2-digit
formatting. The second parameter to appendValue
specifies the
minimum field width, with padding added as needed.
Composite Formatters
This example demonstrates combining multiple formatters into one. We'll create separate date and time formatters, then combine them with a literal separator. This approach promotes reusability of formatter components.
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)); } }
The output will be in format like "Apr 16, 2025 at 02:30 PM". The example shows how to build complex formatters from simpler components. Each sub-formatter can be used independently or combined with others.
Handling Different Calendars
This advanced example shows how to create a formatter for non-ISO calendars. We'll build a formatter for the Japanese Imperial calendar system. The formatter will display dates with Japanese era names.
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)); } }
The output will show the date in Japanese format with era name. For 2025, this would be "令和 7年 4月 16日". The formatter handles the Japanese calendar system correctly, including proper era naming and ordering of components.
Source
Java DateTimeFormatterBuilder Documentation
This tutorial covered the essential features of DateTimeFormatterBuilder
.
With these techniques, you can create sophisticated date/time formatters tailored
to your specific requirements. The builder pattern provides flexibility beyond
standard formatting patterns.
Author
List all Java tutorials.