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 を確かめます。
参考にした公式ドキュメント





