Форматирование составных значений в js-joda опирается на работу с
объектами, реализующими интерфейс TemporalAccessor, где
дата, время и дополнительные компоненты представляют собой единое
значение, но логически состоят из нескольких частей. На практике это
чаще всего LocalDateTime, ZonedDateTime,
OffsetDateTime и их комбинации с часовыми поясами и
смещениями. Форматирование таких структур требует точного управления
шаблонами, локалью и правилами вывода отдельных полей.
В основе системы форматирования лежит DateTimeFormatter,
который преобразует временные объекты в строку и обратно. Форматтер
работает не с конкретными классами, а с абстракцией временных данных,
что позволяет единообразно обрабатывать составные значения.
Форматирование всегда происходит через метод format,
принимающий объект временного типа:
import { DateTimeFormatter } from '@js-joda/core';
import { LocalDateTime } from '@js-joda/core';
const dt = LocalDateTime.of(2026, 1, 15, 10, 30, 45);
const formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
const result = formatter.format(dt);
ISO-форматы являются базовой категорией форматирования и обеспечивают стандартизированное представление составных значений без локализации.
ISO-форматы в js-joda представляют собой заранее определённые
композиции полей даты и времени. Например,
ISO_LOCAL_DATE_TIME включает дату и время без зоны, а
ISO_ZONED_DATE_TIME добавляет идентификатор часового
пояса.
Состав таких форматов можно рассматривать как фиксированную последовательность элементов:
TПри использовании ZonedDateTime форматирование
автоматически включает дополнительные компоненты:
import { ZonedDateTime, ZoneId, DateTimeFormatter } from '@js-joda/core';
const zdt = ZonedDateTime.of(
2026, 1, 15, 10, 30, 45, 0,
ZoneId.of('Europe/Berlin')
);
const formatted = DateTimeFormatter.ISO_ZONED_DATE_TIME.format(zdt);
Наиболее гибкий способ форматирования составных значений —
использование пользовательских шаблонов через
DateTimeFormatter.ofPattern.
Шаблон представляет собой строку, где каждый символ или группа символов соответствует определённому полю временного объекта.
y — годM — месяцd — деньH — часы (24-часовой формат)m — минутыs — секундыS — доли секундыV, z, O, X,
x — часовые поясаПример составного форматирования:
const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss');
const result = formatter.format(dt);
Паттерн объединяет несколько временных компонентов в одну строку, обеспечивая строгий контроль над порядком и разделителями.
При работе с ZonedDateTime добавляется дополнительный
уровень сложности: идентификатор зоны или смещение.
Z — смещение от UTC (+0100)X — ISO-смещение (+01, +0100, +01:00)z — текстовое имя зоны (Europe/Berlin)V — идентификатор зоныПример:
import { ZonedDateTime, ZoneId, DateTimeFormatter } from '@js-joda/core';
const zdt = ZonedDateTime.of(
2026, 5, 24, 14, 45, 0, 0,
ZoneId.of('Asia/Almaty')
);
const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss Z VV');
const result = formatter.format(zdt);
Здесь составное значение включает одновременно локальную дату-время, числовое смещение и идентификатор зоны.
Для более сложных сценариев используется
DateTimeFormatterBuilder, позволяющий собирать формат из
отдельных компонентов. Это особенно важно при работе с составными
значениями, где требуется условная логика или гибкая структура.
import { DateTimeFormatterBuilder } from '@js-joda/core';
const builder = new DateTimeFormatterBuilder()
.appendValue('year')
.appendLiteral('-')
.appendValue('monthOfYear', 2)
.appendLiteral('-')
.appendValue('dayOfMonth');
Такой подход позволяет явно управлять каждым элементом составного значения.
const builder = new DateTimeFormatterBuilder()
.appendValue('hourOfDay', 2)
.appendLiteral(':')
.appendValue('minuteOfHour', 2)
.appendLiteral(':')
.appendValue('secondOfMinute', 2);
Каждый компонент добавляется отдельно, что исключает неоднозначность шаблона.
Составные значения часто содержат необязательные компоненты, например
секунды или миллисекунды. Для этого используются конструкции
optionalStart и optionalEnd.
const formatter = new DateTimeFormatterBuilder()
.appendValue('hourOfDay', 2)
.appendLiteral(':')
.appendValue('minuteOfHour', 2)
.optionalStart()
.appendLiteral(':')
.appendValue('secondOfMinute', 2)
.optionalEnd()
.toFormatter();
В результате секундная часть отображается только при наличии значения.
Форматирование может зависеть от локали, что влияет на порядок компонентов, текстовые представления месяцев и дней недели, а также формат разделителей.
import { Locale } from '@js-joda/locale';
const formatter = DateTimeFormatter
.ofPattern('EEEE, d MMMM yyyy')
.withLocale(Locale.forLanguageTag('ru'));
const result = formatter.format(dt);
Локализация особенно важна при форматировании составных значений, включающих текстовые элементы.
Некоторые элементы временных данных могут быть представлены в текстовом виде:
Для этого используются методы appendText в
DateTimeFormatterBuilder или соответствующие токены в
шаблонах.
const formatter = new DateTimeFormatterBuilder()
.appendValue('dayOfMonth')
.appendLiteral(' ')
.appendText('monthOfYear')
.appendLiteral(' ')
.appendValue('year')
.toFormatter();
Составные значения часто включают наносекунды или миллисекунды. Для
их форматирования используется токен S.
const formatter = DateTimeFormatter.ofPattern('HH:mm:ss.SSS');
Количество символов определяет точность вывода:
S — десятые долиSS — сотыеSSS — миллисекундыНаиболее полные составные значения включают одновременно все компоненты:
const formatter = DateTimeFormatter.ofPattern(
'yyyy-MM-dd HH:mm:ss.SSS VV'
);
Такой формат охватывает:
При форматировании ZonedDateTime все элементы
извлекаются автоматически из одного объекта.
Для составных значений важна выравненность полей. В
DateTimeFormatterBuilder можно задавать минимальную и
максимальную ширину:
const formatter = new DateTimeFormatterBuilder()
.appendValue('dayOfMonth', 2)
.appendLiteral('/')
.appendValue('monthOfYear', 2)
.appendLiteral('/')
.appendValue('year', 4)
.toFormatter();
Это обеспечивает стабильный формат даже при изменении значений.
Форматирование часто включает статические элементы: пробелы, знаки
пунктуации, текстовые маркеры. Они добавляются через
appendLiteral или напрямую в шаблон
ofPattern.
const formatter = DateTimeFormatter.ofPattern('dd.MM.yyyy \'at\' HH:mm');
Литералы позволяют строить человекочитаемые представления составных значений без влияния на структуру временных данных.
Форматирование составных значений тесно связано с обратной операцией — разбором строки. Один и тот же форматтер может использоваться для round-trip преобразований:
const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd HH:mm:ss');
const text = formatter.format(dt);
const parsed = LocalDateTime.parse(text, formatter);
Согласованность шаблона критична для корректного восстановления составных значений.
Некоторые временные типы не содержат всех компонентов. Например,
LocalDate не включает время, а LocalTime не
содержит даты. При попытке форматирования составного шаблона
используется только доступная часть данных, а отсутствующие элементы
либо игнорируются, либо вызывают ошибку в зависимости от структуры
форматтера.
DateTimeFormatterBuilder позволяет явно контролировать
поведение через опциональные блоки и правила заполнения.
Builder API позволяет формировать многоуровневые структуры, где разные части даты и времени комбинируются в единую строку с разными правилами форматирования:
const formatter = new DateTimeFormatterBuilder()
.appendValue('year')
.appendLiteral('-')
.appendValue('monthOfYear')
.appendLiteral('-')
.appendValue('dayOfMonth')
.appendLiteral(' ')
.appendValue('hourOfDay')
.appendLiteral(':')
.appendValue('minuteOfHour')
.appendLiteral(':')
.appendValue('secondOfMinute')
.appendLiteral(' ')
.appendZoneId()
.toFormatter();
Такая конструкция представляет собой полное составное значение, объединяющее календарь, время и зону в единую строку с детализированным контролем каждого элемента.