Дата/время: 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. Семь лет опыта, от веба и SEO до автоматизации в масштабах концерна, сегодня прагматично для среднего бизнеса и с немецким суверенитетом данных.

Сертификаты

  • Сертифицирован Microsoft — PL-900 и AZ-900
  • Сертифицирован UiPath — Automation Developer Associate
Все статьи
Читать далее

Похожие инструкции

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

Избегайте ловушек часовых поясов Luxon в n8n навсегда

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

Стоимость и лицензии n8nКонсалтинг по n8n

  • Проверка выражений Luxon на корректные часовые пояса и форматы
  • Даты счетов и документов без ошибок сдвига
  • Проверка workflow до запуска в продакшн, а не поиск ошибок после