ZetCode

Java DateTimeFormatter Class

Last modified: April 16, 2025

The java.time.format.DateTimeFormatter class provides formatting and parsing of date-time objects. It is part of Java's modern date-time API introduced in Java 8. The class is thread-safe and immutable.

DateTimeFormatter supports predefined formatters, pattern-based formatting, and localized styles. It works with all temporal classes like LocalDate, LocalDateTime, and ZonedDateTime. The class handles both formatting dates to strings and parsing strings to dates.

DateTimeFormatter Class Overview

DateTimeFormatter provides constants for common formats and methods to create custom patterns. Key features include locale-sensitive formatting, pattern syntax similar to SimpleDateFormat, and strict parsing rules.

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);
}

The code above shows key methods of DateTimeFormatter. The class provides flexible formatting options while maintaining thread safety. It replaces the older SimpleDateFormat which had thread-safety issues.

Using Predefined Formatters

Java provides several predefined formatters for common ISO and localized formats. These constants are available as static fields in DateTimeFormatter. They cover most standard date-time representations.

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));
    }
}

This example demonstrates using predefined ISO formatters. The output shows different standard representations of the current date and time. These formatters are useful when working with standardized date formats.

Formatting with Custom Patterns

Custom patterns can be created using the ofPattern method. The pattern syntax uses letters to represent date/time components. The patterns are similar to those used in 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");
    }
}

This example shows various custom formatting patterns. The patterns can include literal text and special pattern letters. Note that some patterns require specific temporal types (like time zones with ZonedDateTime).

Localized Formatting

DateTimeFormatter supports locale-specific formatting through ofLocalized methods and withLocale. This produces output appropriate for different languages and regional conventions.

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));
    }
}

This example demonstrates locale-sensitive formatting. The output varies based on the specified locale and format style. FormatStyle offers SHORT, MEDIUM, LONG, and FULL options for different detail levels.

Parsing Date-Time Strings

DateTimeFormatter can parse strings into date-time objects. The parse method converts text following the formatter's pattern into a temporal object. Strict parsing ensures input validity.

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);
    }
}

This example shows parsing strings into date-time objects. The parser is strict by default, rejecting invalid dates. For lenient parsing, use withResolverStyle(ResolverStyle.LENIENT).

Formatting ZonedDateTime

When working with time zones, DateTimeFormatter can handle zone-specific formatting. The patterns can include zone IDs or offsets. ZonedDateTime provides complete timezone-aware date-time information.

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));
    }
}

This example demonstrates formatting ZonedDateTime with time zone information. Different pattern letters handle zone IDs, offsets, and names. The output shows the same moment in time with different zone representations.

Combining Formatters

DateTimeFormatter instances can be combined or modified using methods like withLocale and withResolverStyle. This allows creating flexible formatters from existing ones.

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));
    }
}

This example shows how to modify and combine formatters. The resolver style controls how lenient the parsing should be. Combined formatters can mix pattern-based and localized formatting.

Source

Java DateTimeFormatter Class Documentation

In this article, we've covered the essential methods and features of the Java DateTimeFormatter class. Mastering these concepts is crucial for effective date-time handling in Java applications.

Author

My name is Jan Bodnar, and I am a dedicated programmer with many years of experience in the field. I began writing programming articles in 2007 and have since authored over 1,400 articles and eight e-books. With more than eight years of teaching experience, I am committed to sharing my knowledge and helping others master programming concepts.

List all Java tutorials.