Класс Java DateTimeFormatter

DateTimeFormatter — важный класс в API даты и времени (пакет java.time), появившийся в Java 8. Он используется для форматирования и разбора объектов даты и времени. Этот класс предоставляет мощный функционал для работы с отображением и преобразованием значений даты и времени.

Проще говоря, DateTimeFormatter имеет две основные цели:

  • Форматирование: преобразует объекты даты и времени (такие как LocalDate, LocalDateTime) в строки в определённом формате
  • Парсинг: преобразует строки, соответствующие формату, в объекты даты и времени

Зачем нужен DateTimeFormatter

До Java 8 мы использовали SimpleDateFormat для обработки форматирования и разбора дат, но у него есть несколько недостатков:

  • Не потокобезопасен
  • Устаревший дизайн
  • Неудобная обработка ошибок

DateTimeFormatter решает эти проблемы:

  • Потокобезопасность: Экземпляры можно безопасно совместно использовать в многопоточных средах
  • Неизменяемый: После создания его нельзя изменить
  • Более богатые предопределённые форматы: Предоставляет большое количество встроенных форматов
  • Улучшенная обработка ошибок: Предоставляет более подробную информацию об ошибках при сбое разбора

Базовое использование

Предопределённые форматтеры

DateTimeFormatter предоставляет множество предопределённых констант форматтера:

Пример

LocalDateTime now = LocalDateTime.now();

// Использовать предопределённый форматтер
System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE));     // 2023-11-15
System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_TIME));     // 14:30:45.123
System.out.println(now.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); // 2023-11-15T14:30:45.123

Пользовательские шаблоны

Вы можете создавать пользовательские форматтеры, используя строки шаблонов:

Пример

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = now.format(formatter);  // Форматирование
System.out.println(formattedDateTime);             // 2023-11-15 14:30:45

// Разбор
LocalDateTime parsedDateTime = LocalDateTime.parse("2023-11-15 14:30:45", formatter);

// Распространённый китайский формат даты
DateTimeFormatter chineseFormatter = DateTimeFormatter.ofPattern(yyyy-MM-dd);
String formattedDate = today.format(chineseFormatter);
System.out.println(Дата в китайском формате: + formattedDate);

// Разбор строки с китайской датой
String chineseDateStr = 2023-05-20;
LocalDate parsedDate = LocalDate.parse(chineseDateStr, chineseFormatter);
System.out.println(Разобранная дата: + parsedDate);

// Другие распространённые форматы
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("MM/dd/yyyy");
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern(yyyy-MM-dd EEEE, Locale.CHINA);

System.out.println(Формат 1: + today.format(formatter1));
System.out.println(Формат 2: + today.format(formatter2));
System.out.println(Формат 3 (с днём недели): + today.format(formatter3));

Локализованные форматы

Вы можете создавать форматтеры на основе разных локалей:

Пример

DateTimeFormatter frenchFormatter =
    DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)
                     .withLocale(Locale.FRENCH);
String frenchDate = now.format(frenchFormatter);
System.out.println(frenchDate);  // 15 novembre 2023

Справочник по буквам шаблона

При создании пользовательских форматов нужно использовать определённые буквы шаблона:

Буква Значение Пример
y год yyyy → 2023
M month MM → 11
d day dd → 15
H Час (0-23) HH → 14
h Час (1-12) hh → 02
m Минута mm → 30
s second ss → 45
S Миллисекунда SSS → 123
E День недели E → Ср
a AM/PM a → PM

Лучшие практики

Повторное использование форматтеров

Поскольку DateTimeFormatter потокобезопасен, рекомендуется определять часто используемые форматтеры как константы:

Пример

public class DateUtils {
    public static final DateTimeFormatter STANDARD_FORMATTER =
        DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
   
    // Использование
    String formatted = LocalDateTime.now().format(STANDARD_FORMATTER);
}

Полный пример:

Пример

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class ExampleTest {

    public static void main(String[] args) {
        // 1. LocalDate пример
        LocalDate currentDate = LocalDate.now();
        System.out.println(Текущая дата: + currentDate);
       
        LocalDate specificDate = LocalDate.of(2023, 5, 20);
        System.out.println(Конкретная дата: + specificDate);

        // 2. LocalTime пример
        LocalTime currentTime = LocalTime.now();
        System.out.println(Текущее время: + currentTime);
       
        LocalTime specificTime = LocalTime.of(14, 30, 15);
        System.out.println(Конкретное время: + specificTime);

        // 3. Пример LocalDateTime
        LocalDateTime currentDateTime = LocalDateTime.now();
        System.out.println(Текущая дата и время: + currentDateTime);
       
        LocalDateTime specificDateTime = LocalDateTime.of(2023, 5, 20, 14, 30, 15);
        System.out.println(Конкретная дата и время: + specificDateTime);

        // 4. Пример DateTimeFormatter
        // Базовое форматирование
        DateTimeFormatter basicFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        System.out.println(Базовое форматирование: + currentDate.format(basicFormatter));

        // Китайское форматирование
        DateTimeFormatter chineseFormatter = DateTimeFormatter.ofPattern(yyyy-MM-dd, Locale.CHINA);
        System.out.println(Китайская дата: + currentDate.format(chineseFormatter));

        // Форматирование по-китайски с днём недели
        DateTimeFormatter weekFormatter = DateTimeFormatter.ofPattern(yyyy-MM-dd EEEE, Locale.CHINA);
        System.out.println(Китайская дата с днём недели: + currentDate.format(weekFormatter));

        // Форматирование времени
        DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern(HH:mm:ss);
        System.out.println(Китайское время: + currentTime.format(timeFormatter));

        // Форматирование даты и времени
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println(Стандартная дата и время: + currentDateTime.format(dateTimeFormatter));

        // Разбор даты
        String dateStr = "2023-05-20";
        LocalDate parsedDate = LocalDate.parse(dateStr, basicFormatter);
        System.out.println(Разобранная дата: + parsedDate);

        // Разбор китайской даты
        String chineseDateStr = 2023-05-20;
        LocalDate parsedChineseDate = LocalDate.parse(chineseDateStr, chineseFormatter);
        System.out.println(Разобранная китайская дата: + parsedChineseDate);
    }
}

Вывод:

当前日期: 2025-05-01
特定日期: 2023-05-20
当前时间: 10:46:38.591747
特定时间: 14:30:15
当前日期时间: 2025-05-01T10:46:38.592002
特定日期时间: 2023-05-20T14:30:15
基本格式化: 2025-05-01
中文日期: 2025年05月01日
带星期的中文日期: 2025年05月01日 星期四
中文时间: 10时46分38秒
标准日期时间: 2025-05-01 10:46:38
解析后的日期: 2023-05-20
解析后的中文日期: 2023-05-20

Обработка исключений разбора

Следует обрабатывать возможные исключения при разборе строк:

Пример

try {
    LocalDateTime dateTime = LocalDateTime.parse("2023-11-15", formatter);
} catch (DateTimeParseException e) {
    System.err.println(Не удалось разобрать дату/время: + e.getMessage());
}

Учитывайте часовые пояса

Если вам нужно обрабатывать часовые пояса, можно использоватьZonedDateTimeи шаблоны с указанием часового пояса:

Пример

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime.format(formatter));  // 2023-11-15 14:30:45 CST

Итог

DateTimeFormatter — мощный инструмент для форматирования и разбора в API даты и времени Java 8. По сравнению со старым SimpleDateFormat он безопаснее, гибче и проще в использовании. Освоение DateTimeFormatter позволяет более эффективно обрабатывать различные требования к формату даты и времени.

Запомните ключевые моменты:

  • Используйте предопределённые форматтеры для распространённых форматов
  • Используйте ofPattern() для создания пользовательских форматов
  • Учитывайте требования локализации и часового пояса
  • Повторно используйте потокобезопасные экземпляры форматтера
  • Правильно обрабатывайте исключения парсинга
Другие расширения