Дата/время: Luxon, немецкие форматы, ловушки часовых поясов

Luxon в n8n: создавай немецкие форматы даты с помощью toFormat и setLocale и избегай типичных ловушек часовых поясов в выражениях.

n8n обрабатывает дату и время внутренне через библиотеку JavaScript Luxon, а не через нативный объект `Date` JavaScript. Обычно это замечаешь только тогда, когда workflow выводит дату, отличающуюся на час, название месяца появляется на английском вместо немецкого, или документ вдруг оказывается не в том дне в конце месяца. Как только ты понимаешь, как Luxon четко разделяет часовой пояс, язык и формат, именно эти ошибки можно целенаправленно избежать, и ты сохраняешь контроль над тем, какая дата в итоге действительно окажется в счете, CRM или таблице.

Эта статья сознательно сосредоточена на форматировании даты и времени в выражениях и в Date & Time Node, а не на логике часовых поясов Schedule Trigger или Cron-выражений. Это отдельная тема со своими подводными камнями, которая заслуживает отдельного рассмотрения.

Почему n8n вообще использует Luxon

Чистый JavaScript не имеет встроенной концепции для часовых поясов или языковых форматов, выходящей за рамки самого основного. Luxon как раз заполняет этот пробел: каждая дата, которую n8n генерирует внутренне, например через `$now` или `$today`, является объектом Luxon `DateTime` с собственным часовым поясом, собственным языком (locale) и собственными методами для вычислений, сравнения и форматирования. Согласно официальной документации по работе с датой и временем в n8n, значения даты передаются между нодами в виде строк и должны быть заново распознаны с помощью функций Luxon для вычислений или форматирования. Нативный JavaScript `Date()` не учитывает часовой пояс, установленный в n8n, поэтому документация прямо рекомендует использовать Luxon для всего, что связано с датой и временем.

Форматирование даты в выражениях

Для собственно форматирования в выражениях доступно несколько путей, по-разному подходящих для немецких требований:

  • `.toFormat(fmt)`: нативный метод Luxon, с помощью которого ты сам собираешь формат из фиксированных токенов, например `dd.MM.yyyy`. Он работает везде, в том числе в Code Node.
  • `.toLocaleString(opts)`: возвращает локализованный, то есть зависящий от языка, формат. Без заданной locale результат ориентируется на язык по умолчанию инстанса n8n, что на практике часто означает английский.
  • `format()`: собственное расширение n8n языка выражений для форматирования дат, которое, согласно справочнику выражений DateTime, недоступно в Code Node. Там вместо этого используется нативный `.toFormat()`.
  • Предустановленные форматы в Date & Time Node: Node содержит фиксированные пресеты, такие как `MM/DD/YYYY` или `YYYY-MM-DD`, а также опцию для собственного формата. Согласно документации по Date & Time Node, n8n поддерживает для этого все форматы, которые известны самому Luxon, при этом токены чувствительны к регистру.

Для чисто числовой немецкой даты обычно достаточно `.toFormat()` с фиксированным шаблоном токенов, тогда как `.toLocaleString()` и `.setLocale()` становятся важны, как только на немецком должны появиться полные названия месяцев или дней недели.

Корректное создание немецких форматов

Для классической немецкой записи `TT.MM.JJJJ` достаточно фиксированного выражения без зависимости от locale:

  • `{{$now.toFormat('dd.MM.yyyy')}}` дает, например, `20.07.2026`.
  • `{{$now.toFormat('dd.MM.yyyy HH:mm')}}` дополняет время в 24-часовом формате.

Как только в игру вступают полные названия, например для счета или рассылки, тебе дополнительно нужна немецкая locale, иначе название месяца будет выведено на английском:

  • `{{$now.setLocale('de-DE').toLocaleString({month: 'long', day: 'numeric', year: 'numeric'})}}` дает результат вроде `20. Juli 2026`.
  • `{{$now.setLocale('de-DE').monthLong}}` напрямую возвращает полное название месяца, например `Juli`.

Важно: `.setLocale()` меняет исключительно язык вывода, а не часовой пояс. Обе настройки нужно устанавливать отдельно друг от друга, иначе ты получишь немецкое слово для месяца, но при определенных обстоятельствах все равно неверное время.

Ловушки часовых поясов при форматировании

Большинство ошибок возникает не из-за самого формата, а из-за часового пояса, в котором происходит форматирование. Несколько ловушек, которые постоянно встречаются на практике:

  • Часовой пояс инстанса по умолчанию вместо Europe/Berlin: без явной настройки самостоятельно размещенный инстанс n8n, согласно документации, по умолчанию использует `America/New York`, а в n8n Cloud система откатывается на GMT. `$now` и `$today` ориентируются на этот часовой пояс инстанса, если только собственная настройка workflow или переменная окружения `GENERIC_TIMEZONE` не задают иное. Тот, кто это упускает, получает временные метки, отклоняющиеся на несколько часов от немецкого времени.
  • Форматирование без предварительного `.setZone()`: `.toFormat()` и `.toLocaleString()` всегда выводят время в том часовом поясе, который в данный момент имеет объект `DateTime`, а не автоматически Europe/Berlin. Если дата приходит из API в UTC или в чужом часовом поясе, тебе следует сначала пересчитать ее с помощью `.setZone('Europe/Berlin')` и только потом форматировать, иначе документ, созданный в 23:30 по немецкому времени, вдруг окажется в отчете на следующем дне.
  • Летнее и зимнее время: Europe/Berlin дважды в год меняет смещение относительно UTC. Если ты вычисляешь с помощью `.plus({days: n})` через такой переход, а затем форматируешь время, временная часть может сдвинуться на час, хотя календарный день верен. Для сравнений только даты без времени это обычно некритично, но для процессов, чувствительных ко времени, это следует учитывать.
  • Передача `.toISO()` со смещением: ISO-строка Luxon по умолчанию содержит смещение часового пояса, например `+02:00`. Системы, которые вместо этого ожидают чистый UTC или строку без смещения, интерпретируют это значение неверно. Проверь в целевой системе, какой формат действительно ожидается, прежде чем слепо передавать результат.

Практический пример: корректный вывод даты счета

Типичный случай из практики: workflow получает дату документа из API, который выдает временные метки в UTC, и должен сгенерировать из нее немецкую дату счета. Выражение для этого в совокупности выглядит так:

  • `{{ $json.createdAt.toDateTime().setZone('Europe/Berlin').setLocale('de-DE').toFormat('dd.MM.yyyy') }}`

Порядок здесь не случаен: сначала нативная временная метка JavaScript преобразуется в Luxon `DateTime`, затем сдвигается в нужный часовой пояс, после этого устанавливается язык, и только в конце происходит форматирование. Если поменять местами шаги часового пояса и форматирования, ты получишь корректно выглядящую немецкую дату, но, возможно, для неверного календарного дня.

Часто задаваемые вопросы

В чем разница между `.toFormat()` и `.toLocaleString()`?

`.toFormat()` следует фиксированному, определенному тобой самим шаблону токенов, например `dd.MM.yyyy`, и всегда выдает одинаковый макет независимо от locale. `.toLocaleString()`, напротив, ориентируется на установленный язык и автоматически подстраивает порядок и написание, что особенно заметно при полных названиях месяцев или дней недели.

Почему название месяца отображается на английском, хотя я работаю в Германии?

Без явного `.setLocale('de-DE')` Luxon использует язык по умолчанию инстанса n8n, который часто установлен на английский. Часовой пояс инстанса и его язык — это две отдельные настройки, поэтому правильно настроенный `Europe/Berlin` сам по себе еще не гарантирует немецкое название месяца.

Нужно ли мне вручную устанавливать часовой пояс для каждой даты?

Всегда, когда дата приходит из внешнего источника, такого как API, база данных или форма, да. Такие значения часто представлены в UTC или в чужом часовом поясе, и только `$now` соответственно `$today` автоматически следуют настроенному в n8n часовому поясу инстанса или workflow.

Относится ли это также к Schedule Trigger или Cron-выражениям?

Нет, там действуют собственные правила для самого времени выполнения, а не для форматирования значений даты в выражениях. Эта статья посвящена исключительно тому, как корректно форматируется уже существующая дата внутри workflow.

Как узнать, какие токены формата поддерживает Luxon?

Согласно документации по Date & Time Node, n8n поддерживает все токены, известные самому Luxon, при этом заглавные и строчные буквы имеют каждая свое собственное значение. Для полного обзора всех доступных токенов стоит заглянуть в связанный справочник форматирования Luxon прямо из документации n8n.

О NordFlux

NordFlux UG (haftungsbeschränkt)

NordFlux создаёт цифровых сотрудников для организаций: автоматизации и КИ-агентов, которые берут на себя повторяющуюся работу. Вы сохраняете контроль.

Больше о нас
Бесплатный первичный анализ

Конкретные вопросы по автоматизации или КИ?

В рамках бесплатного первичного анализа мы напрямую обсудим Ваш случай. Без обязательств.