在自动化工作流中,日期和时间数据处理是最常见的需求之一。无论是计算两个日期之间的天数、格式化日期显示,还是处理不同时区的时间,n8n 的 Luxon 库都能完美解决。本教程将带你从零开始,学会在 n8n 中高效使用 Luxon,让日期时间处理变得简单易懂。
Luxon 是一个功能强大的 JavaScript 日期时间库,专门为了解决原生 JavaScript Date 对象的复杂性而创建。它提供了更加直观和易用的 API,让你能够轻松处理:
为什么选择 Luxon 而不是原生 JavaScript?
原生 JavaScript:
// ❌ 不够直观,需要记住很多 API 细节
new Date('2019-06-23') // 容易出错,可能产生错误的时区Luxon:
// ✅ 清晰明确,指定格式
DateTime.fromISO('2019-06-23')
DateTime.fromFormat("23-06-2019", "dd-MM-yyyy")n8n 为你提供了两个内置的时间变量,无需额外导入:
| 变量 | 说明 | 示例输出 |
|---|---|---|
$now | 当前时刻(精确到秒) | 2025-12-05T11:21:00.000+00:00 |
$today | 当前日期(时间部分为 00:00:00) | 2025-12-05T00:00:00.000+00:00 |
重点:这两个变量可以在:
{{}} 包裹)$now 和 $today)需求:在工作流中获取当前时刻
在表达式中:
// 获取当前时刻(包含时间)
{{$now}}
// 获取当前日期(不包含时间,午夜)
{{$today}}在 Code 节点中:
// 当前时刻对象
const now = $now;
console.log(now); // 输出 Luxon DateTime 对象
// 当前日期对象
const today = $today;
console.log(today);需求:获取 7 天前的日期,或 30 天后的日期
在表达式中:
// 获取 7 天前的日期
{{$today.minus({days: 7})}}
// 获取 30 天后的日期
{{$today.plus({days: 30})}}
// 获取 3 个月前的日期
{{$today.minus({months: 3})}}
// 获取 1 年后的日期
{{$today.plus({years: 1})}}在 Code 节点中:
// 7 天前
let sevenDaysAgo = $today.minus({days: 7});
// 结合多个时间单位
let futureDate = $today.plus({
years: 1,
months: 2,
days: 15
});
// 输出给下一个节点
return [{json: {sevenDaysAgo, futureDate}}];需求:将日期转换为易读的格式
常用格式转换:
// 表达式方式
{{$today.toLocaleString()}} // 23/06/2019(地区格式)
{{$today.toFormat("dd/MM/yyyy")}} // 23/06/2019
{{$today.toFormat("MMMM dd, yyyy")}} // June 23, 2019
{{$today.toFormat("yyyy-MM-dd HH:mm:ss")}} // 2019-06-23 14:30:45
// Code 节点方式
let dateString = $today.toFormat("dd/MM/yyyy");
let humanReadable = $today.toLocaleString();格式化标记速查表:
| 标记 | 说明 | 示例 |
|---|---|---|
yyyy | 4 位年份 | 2025 |
MM | 2 位月份 | 01, 12 |
dd | 2 位日期 | 05, 25 |
HH | 24 小时制小时 | 00, 23 |
mm | 分钟 | 00, 59 |
ss | 秒钟 | 00, 59 |
MMMM | 月份全名 | January, December |
MMM | 月份缩写 | Jan, Dec |
EEEE | 星期全名 | Monday, Sunday |
EEE | 星期缩写 | Mon, Sun |
需求:处理来自其他节点的日期字符串
从标准格式转换(ISO 8601):
// 表达式方式
// 假设输入数据中有一个 date 字段,值为 "2019-06-23"
{{DateTime.fromISO($json.date)}}
// Code 节点方式
const luxonDate = DateTime.fromISO("2019-06-23");从自定义格式转换:
// 假设日期格式为 "23-06-2019"
// 表达式方式
{{DateTime.fromFormat($json.date, "dd-MM-yyyy")}}
// Code 节点方式
const luxonDate = DateTime.fromFormat("23-06-2019", "dd-MM-yyyy");
const luxonDate2 = DateTime.fromFormat($json.dateField, "dd/MM/yyyy");⚠️ 重要:注意格式标记的大小写,YYYY 和 yyyy 的含义不同!
需求:计算订单创建到现在已经过了多少天
在表达式中:
// 计算从某个日期到今天经过了多少天
{{$today.diff(DateTime.fromISO($json.orderDate), 'days').toObject().days}}
// 计算距离圣诞节还有多少天
{{$today.diff(DateTime.fromISO($today.year + '-12-25'), 'days').toObject().days}}在 Code 节点中:
// 从 order_date 到现在的天数差
const orderDate = DateTime.fromISO($json.order_date);
const daysDiff = $today.diff(orderDate, 'days').toObject();
console.log(`距离订单创建已经 ${daysDiff.days} 天`);
// 同时获取多个时间单位
const duration = $today.diff(orderDate, ['years', 'months', 'days']).toObject();
console.log(`${duration.years} 年 ${duration.months} 个月 ${duration.days} 天`);
return [{json: {daysPassed: daysDiff.days, duration}}];n8n 中的时区规则:
n8n 默认使用的时区是 美国纽约时区 (America/New York),但你可以在工作流设置中修改。所有 Luxon 操作都会遵守这个时区设置。
// 在表达式中查看当前时区
{{$today}} // 会基于实例或工作流的时区设置
// 如果需要特定时区,在 Code 节点中:
const tokioTime = $now.setZone('Asia/Tokyo');
const nyTime = $now.setZone('America/New_York');
console.log(tokioTime.toLocaleString()); // 东京时间,易读格式
console.log(nyTime.toLocaleString()); // 纽约时间,易读格式现在让我们组合使用所有学到的知识,创建一个实用的工作流:自动生成周报
{
"nodes": [
{
"parameters": {},
"id": "abc123start",
"name": "Start",
"type": "n8n-nodes-base.start",
"typeVersion": 1,
"position": [250, 300]
},
{
"parameters": {
"mode": "runOnceForAllItems",
"code": "// 计算上周的日期范围\nconst today = $today;\n\n// 上周的第一天(上周一)\nconst lastMonday = today.minus({days: today.weekday}).minus({days: 6});\n\n// 上周的最后一天(上周日)\nconst lastSunday = lastMonday.plus({days: 6});\n\n// 周报的标题\nconst reportTitle = `周报 (${lastMonday.toFormat('MM/dd')} - ${lastSunday.toFormat('MM/dd')})`;\n\n// 距离本周末的天数\nconst daysToWeekend = today.diff(\n today.endOf('week'), \n 'days'\n).toObject().days;\n\n// 返回结果\nreturn [{\n json: {\n weekStart: lastMonday.toFormat('yyyy-MM-dd'),\n weekEnd: lastSunday.toFormat('yyyy-MM-dd'),\n reportTitle: reportTitle,\n daysToWeekend: Math.abs(daysToWeekend),\n formattedRange: `${lastMonday.toFormat('MMMM dd')} 至 ${lastSunday.toFormat('MMMM dd, yyyy')}`,\n generatedAt: $now.toFormat('yyyy-MM-dd HH:mm:ss')\n }\n}];"
},
"id": "def456code",
"name": "生成周报日期",
"type": "n8n-nodes-base.code",
"typeVersion": 1,
"position": [450, 300]
},
{
"parameters": {
"jsonData": "={\"weeklyReport\": $('生成周报日期').first().json}"
},
"id": "ghi789output",
"name": "输出结果",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [650, 300]
}
],
"connections": {
"Start": {
"main": [
[
{
"node": "生成周报日期",
"type": "main",
"index": 0
}
]
]
},
"生成周报日期": {
"main": [
[
{
"node": "输出结果",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"timezone": "Asia/Shanghai"
}
}当你运行这个工作流时,会得到类似这样的输出:
{
"weekStart": "2025-11-24",
"weekEnd": "2025-11-30",
"reportTitle": "周报 (11/24 - 11/30)",
"daysToWeekend": 4,
"formattedRange": "November 24 至 November 30, 2025",
"generatedAt": "2025-12-05 11:21:30"
}| 需求 | 表达式示例 | Code 节点示例 |
|---|---|---|
| 当前日期 | {{$today}} | const date = $today; |
| 7天前 | {{$today.minus({days: 7})}} | $today.minus({days: 7}) |
| 格式化 | {{$today.toFormat("dd/MM/yyyy")}} | $today.toFormat("dd/MM/yyyy") |
| 字符串转日期 | {{DateTime.fromISO($json.date)}} | DateTime.fromISO("2025-12-05") |
| 计算差值 | {{$today.diff(date, 'days')}} | $today.diff(date, ['days']) |
yyyy 和 YYYY 不一样{{}} 包裹,Code 节点中直接使用 - 两种方式都支持// 一行代码完成多个操作
const result = $today
.minus({days: 7}) // 7天前
.endOf('week') // 周末
.toFormat('MMMM dd, yyyy'); // 格式化
// 结果:如果今天是 12月5日,则输出 November 30, 2025// 判断是否超期
const dueDate = DateTime.fromISO($json.dueDate);
const isOverdue = $today > dueDate;
// 在表达式中
{{$today > DateTime.fromISO($json.deadline) ? "已超期" : "未超期"}}// 在 Code 节点中处理数组
const dates = $json.datesList;
const formattedDates = dates.map(date =>
DateTime.fromISO(date).toFormat('yyyy-MM-dd')
);
return [{json: {formatted: formattedDates}}];| 错误 | 原因 | 解决方案 |
|---|---|---|
Cannot read property 'minus' | 传入了字符串而非 Luxon 对象 | 使用 DateTime.fromISO() 转换 |
| 日期格式不对 | 格式标记错误 | 检查大小写,参考标记速查表 |
| 时区不对 | 没有设置工作流时区 | 在工作流设置中修改时区 |
| undefined 错误 | 使用了不存在的字段 | 检查数据源是否真的有该字段 |
[1] 官方文档: https://docs.n8n.io/code/cookbook/luxon/
[2] n8n系列教程: https://www.undsky.com/blog/?category=n8n%E6%95%99%E7%A8%8B#