LINE予約「LUCA」の機能と料金はこちら

n8n「DateTime is not a constructor」の原因と直し方(Luxon)

実務ノート 実務ノート 公開

n8n の Code ノードで日付を扱おうとして new DateTime() と書くと、実行した瞬間にワークフローが止まります。「DateTime is not a constructor」で調べて来た方も多いと思いますが、実際に出るエラー文は書き方によって変わり、DateTime という語が出ないこともあります。この記事では、弊社の本番で起きたことと、n8n と Luxon のソースで確かめた原因、直し方をまとめます。

この記事の結論

  • n8n の Code ノードで使える DateTime は、日付を扱うライブラリ Luxon の DateTime クラスそのものです。日時の値は new で作らず、DateTime.now() や DateTime.fromISO() のようなクラスのメソッドで作ります。
  • new DateTime() と書いたときのエラー文は「Cannot read properties of undefined (reading ‘zone’)」です。DateTime という語が入らないので、原因にたどり着きにくいです。
  • 「is not a constructor」の形になるのは、new DateTime.now() のようにメソッドへ new を付けたときです。
  • 直し方は new を外し、目的に合うメソッドへ置き換えることです。引数を渡した new DateTime(...) は止まらずに今の日時になるので、これも必ず書き換えます。

実際に起きたこと

2026-05-05 に、検索対策(SEO)の定期処理を回すワークフロー群をまとめて点検しました。以前の調べでは「7本中6本が動いていない」とされていましたが、実行の記録を見直すと半分は誤りでした。本当に失敗していたのは3本で、そのうち1本がこの記事の不具合です。

弊社で動かしているそのワークフローは、次のエラーで失敗していました。

Cannot read properties of undefined (reading 'zone')

エラー文にあるのは zone という語だけです。日付の処理で止まったと分かる手がかりがありません。Code ノードの中を読むと、new DateTime() と書いている箇所がありました。同じ書き方は2つの Code ノードにあり、どちらも DateTime.now() に置き換えて直しました。

その翌日の 2026-05-06 に、ワークフローを作る・直す・有効にする前に必ず通す点検を、弊社の決まりにしました。点検の項目では、new DateTime() を「実行時即死級」という最も重い区分に入れています。Code ノードを書き換えた直後にも、この点検を通します。

原因

Code ノードの DateTime は Luxon のクラスそのもの

ここからは n8n 2.19.2 のソースで確かめた内容です。Code ノードの JavaScript は、タスクランナーという別の実行環境で動きます。タスクランナーは、コードを動かす場所(コンテキスト)を作るときに、ワークフローのデータを読むための一覧を展開して入れます。

...this.getNativeVariables(),
...dataProxy,
...this.buildRpcCallObject(taskId),

その一覧を作る WorkflowDataProxy を見ると、DateTime には Luxon の DateTime がそのまま入っています。$now と $today も Luxon で作った値です。

$now: luxon_1.DateTime.now(),
$today: luxon_1.DateTime.now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }),
(中略)
DateTime: luxon_1.DateTime,
Interval: luxon_1.Interval,
Duration: luxon_1.Duration,

n8n 2.19.2 に入っている Luxon は 3.7.2 です。n8n が包み直した別物ではないので、使い方は Luxon の決まりに従います。タスクランナーの仕組みそのものは、n8nのCodeノードで「fetch is not defined」が出る原因と直し方 で詳しく書いています。

Luxon のコンストラクタは内部用

コンストラクタとは、new を付けて呼んだときに動く、値を組み立てる関数です。Luxon 3.7.2 の DateTime のコンストラクタには「@access private」という注記が付いています。ライブラリの内部で使うためのもので、利用者が直接呼ぶ前提ではありません。中身の最初の行は次のとおりです。

constructor(config) {
  const zone = config.zone || Settings.defaultZone;

引数の config は、Luxon が内部で使う設定のオブジェクトです。new DateTime() と引数なしで呼ぶと、config は undefined になります。undefined の zone を読もうとして、TypeError(値の型が合わないときのエラー)が起きます。これが「Cannot read properties of undefined (reading ‘zone’)」の正体です。

正しい作り方は、DateTime.now() の中身を見ると分かります。now は空のオブジェクトを渡して、内部でコンストラクタを呼んでいます。

static now() {
  return new DateTime({});
}

Luxon のソースにあるクラスの説明にも、作るときはクラスのメソッドを使うように書かれています。部品から作るなら local、utc、fromObject、ISO などの決まった形式の文字列からなら fromISO、独自の形式の文字列からなら fromFormat、JavaScript の Date からなら fromJSDate です。

「is not a constructor」になる書き方

JavaScript には、new を付けて呼べる関数と、付けて呼べない関数があります。MDN は、メソッドはコンストラクタにならず、new で呼ぶと TypeError を投げると説明しています。例として、new obj.method() が「obj.method is not a constructor」になるコードも載っています。

Luxon の now や fromISO は、static now() のように書かれたクラスのメソッドです。そのため new DateTime.now() と書くと、MDN の例と同じ形で「DateTime.now is not a constructor」になります。一方、DateTime そのものはクラスなので、new DateTime() は「not a constructor」にはなりません。先ほどの zone のエラーになります。

エラーにならない書き方がいちばん危ない

引数を渡して new DateTime(new Date()) や new DateTime('2026-05-05') と書いた場合は、ソースを読む限りエラーになりません。コンストラクタが渡された値から読むのは zone、invalid、ts といった Luxon の内部の項目です。Date や文字列には、その項目がありません。ts が無いときは、次の行で今の時刻が入ります。

this.ts = isUndefined(config.ts) ? Settings.now() : config.ts;

つまり、渡した日付は使われず、今の日時の値ができます。ワークフローは止まらないので、気づくのが遅れます。new DateTime( を見つけたら、引数があってもなくても書き換えてください。

直し方

残っている new DateTime を探す

まず、Code ノードに new DateTime が残っていないかを調べます。ワークフローの中身は n8n の API で JSON として取り出せます。取り出したファイルを、正規表現で数えます。

curl -s -H "X-N8N-API-KEY: XXXX" \
  http://localhost:5678/api/v1/workflows/<ワークフローID> \
  -o wf.json
python3 -c "import re; print(len(re.findall(r'new\s+DateTime\b', open('wf.json').read())))"

この正規表現は、new DateTime( と new DateTime.now( の両方を拾います。件数が0でなければ、該当する Code ノードを開いて1つずつ書き換えます。

目的に合うメソッドへ置き換える

やりたいこと 書いてはいけない形 正しい書き方
今の日時 new DateTime() DateTime.now()
ISO 8601 の文字列から new DateTime('2026-05-05') DateTime.fromISO('2026-05-05')
JavaScript の Date から new DateTime(new Date()) DateTime.fromJSDate(new Date())
独自の形式の文字列から new DateTime('2026/05/05') DateTime.fromFormat('2026/05/05', 'yyyy/MM/dd')

今の日時は、Code ノードでは $now でも取れます。上で見たとおり、n8n のソースでは $now: luxon_1.DateTime.now() と定義されています。n8n の公式ドキュメントも、Code ノードで JavaScript の Date を Luxon の値に変えるときは DateTime.fromJSDate() を使うよう書いています。

書き換えの例

今日の日付を文字列にする Code ノードの例です。書き換え前は、実行した瞬間に zone のエラーで止まります。

// 書き換え前
const today = new DateTime().toFormat('yyyy-MM-dd');
return [{ json: { today } }];

new を外して now を呼ぶだけです。

// 書き換え後
const today = DateTime.now().toFormat('yyyy-MM-dd');
return [{ json: { today } }];

文字列から作るときは、読めたかどうかも確かめます。Luxon の fromISO は、読めない文字列を渡しても例外を投げません。「無効」の印が付いた値を返します。止めたいときは、次のように自分で例外を投げます。

return $input.all().map((item) => {
  const d = DateTime.fromISO(String(item.json.date || ''));
  if (!d.isValid) {
    throw new Error('日付を読めません: ' + item.json.date + '(' + d.invalidReason + ')');
  }
  return { json: { ...item.json, date: d.toISO() } };
});

直ったかを確かめる

  • 編集画面でその Code ノードだけを実行し、エラーが出ずに日付が返ることを見ます。
  • 出力された日時の末尾の時差(日本時間なら +09:00)が、想定しているタイムゾーンになっているかを見ます。
  • API で取り出した JSON をもう一度数え、new DateTime が0件になったことを確かめます。
  • スケジュールで動くワークフローなら、次の実行が成功で終わるところまで見届けます。

それでも直らないとき

エラー文が「DateTime is not a constructor」そのもの

DateTime の後ろにメソッド名が付かず、DateTime という名前そのものが「not a constructor」と言われる場合です。Code ノードの DateTime は Luxon のクラスなので、そのまま使っていればこの形にはなりません。そのコードの中で、DateTime という名前が別の値を指していると考えられます。同じ名前の変数を自分で宣言していないかを探してください。

何が入っているかは、次の1行で見られます。MDN によると、クラスに typeof を使うと “function” になります。function 以外が返れば、Luxon のクラスではありません。

return [{ json: { type: typeof DateTime } }];

式の欄に DateTime だけを書いた

Code ノードではなく、ノードの設定欄の式(二重の波かっこの中)で使う場合です。n8n 2.19.2 のソースでは、式の結果が DateTime のクラスそのものだと、次のエラーを出すようになっています。

this is a DateTime, please access its methods

{{ DateTime.now().toISO() }} のように、メソッドまで書いてください。式の中でも考え方は同じです。

エラーは消えたのに日付が入らない

fromISO などに読めない文字列を渡すと、例外にならずに「無効」の値ができます。無効の値の toISO() は null を返し、toFormat() は「Invalid DateTime」という文字を返します。isValid で有効かどうかを、invalidReason で理由を見てください。fromISO で読めなかったときの理由は unparsable です。

時刻がずれる

Luxon が使うタイムゾーンは、ワークフローの設定のタイムゾーンです。設定が無ければ、n8n 全体の既定の値になります。ソースでは次のように決めています。

this.timezone = workflow.settings?.timezone ?? (0, global_state_1.getGlobalState)().defaultTimezone;
luxon_1.Settings.defaultZone = this.timezone;

タスクランナーは既定の値を環境変数 GENERIC_TIMEZONE から読みます。設定が無ければ America/New_York です。日本時間で動かしたいのにずれるときは、n8nのスケジュールがずれる原因とタイムゾーン設定の記事 を参考にしてください。

まとめ

  • Code ノードの DateTime は Luxon のクラスそのもので、コンストラクタは Luxon の内部用です。
  • new DateTime() は「Cannot read properties of undefined (reading ‘zone’)」で止まります。
  • new DateTime.now() のようにメソッドへ new を付けると「is not a constructor」になります。
  • 引数つきの new DateTime(...) は止まらずに今の日時になるので、見つけたら必ず書き換えます。
  • DateTime.now()、fromISO()、fromJSDate()、fromFormat() に置き換え、文字列から作ったら isValid を確かめます。

参考にした公式ドキュメント

n8nの点検と構築のご相談

「Codeノードの日付の処理で止まる」といったn8nの不具合の点検や、業務の自動化の仕組みづくりをお引き受けしています。

お問い合わせはこちら

この記事を書いた人

貫名 孝夫(マルタマーケティング株式会社 代表取締役)。n8nで140本を超えるワークフローを本番で動かしながら、実際に起きた不具合と直し方を記録しています。会社概要