笔者按:为什么你要放弃 n8n 的 Date 节点?
大家好,我是 N8N大学 的主编。在自动化这条路上,我见过太多人被 n8n 自带的 Date 节点折磨得死去活来。它能做什么?获取当前时间、加减几天。仅此而已。
但现实世界的业务逻辑往往复杂得令人发指:“帮我找出上个月的最后一个周五”、“把这个 ISO 时间转换成‘刚刚’这种人类可读格式”、“计算两个日期之间的工作日天数”。这时候,Date 节点直接瘫痪,你不得不搭建一个丑陋的、由十几个小节点组成的逻辑链。
今天,笔者就要带你打破这个僵局。我们将深入探讨如何利用 JavaScript 生态中最强大的两个时间库——Day.js 和 Moment.js,在 Code 节点里一行代码解决复杂的时间计算。这不仅是效率的提升,更是你成为 n8n 高阶玩家的必修课。
核心定义:代码节点中的时间“瑞士军刀”
在 n8n 中,Code 节点是你的“万能钥匙”。默认情况下,它运行在 Node.js 环境中。这意味着,你可以直接通过 npm 安装并使用任何 JavaScript 库,当然也包括 Day.js 和 Moment.js。
为什么我们要引入外部库?因为原生的 JavaScript 日期处理(new Date())简直是反人类的。而 Moment.js 曾经是业界的王者,功能极其强大;Day.js 则是它的轻量级挑战者,拥有几乎相同的 API,但体积只有 2KB。
Day.js vs Moment.js:我该如何选择?
对于 n8n 用户来说,这是一个幸福的烦恼。但在投入生产之前,你需要了解它们的区别。
| 特性 | Day.js | Moment.js |
|---|---|---|
| 体积 | 极小 (2KB) | 较大 (几十 KB) |
| API 风格 | 与 Moment.js 高度兼容 | 原生 API |
| 不可变性 | 默认不可变 (更安全) | 可变 (容易产生副作用) |
| 维护状态 | 活跃,现代 | 维护模式,不再推荐新项目使用 |
笔者的建议: 除非你有必须使用 Moment.js 的历史遗留代码需求,否则请无脑选择 Day.js。它更轻、更快,且符合现代 JS 开发标准。
核心实操:在 n8n 中引入并使用时间库
很多新手看到这里会问:“我怎么在 n8n 里安装 npm 包?” 别急,n8n 早就为我们想到了这一点。我们不需要在服务器上运行 npm install,而是利用 Code 节点的特殊机制。
第一步:搞定 Day.js 的引入
在 n8n 的 Code 节点(推荐使用 JavaScript 模式)中,你有两种方式引入 Day.js:
方式一:使用 n8n 的内置模块(推荐)
n8n 预装了 Day.js。你可以直接使用 require:
const dayjs = require('dayjs');
方式二:使用高级特性(如时区、自定义格式)
如果你需要处理时区,需要加载插件。Day.js 的插件机制非常灵活:
const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');
const timezone = require('dayjs/plugin/timezone');
dayjs.extend(utc);
dayjs.extend(timezone);
第二步:实战演练——复杂时间计算
假设你的上一个节点传来了一条数据,包含一个字段 eventDate,格式为 2023-10-27T10:00:00Z。现在你需要:
- 判断这个日期是否在未来。
- 如果是未来的日期,计算它距离现在还有多少天。
- 如果是过去的日期,计算它距离现在过去了多少个月。
- 最后,将结果格式化为
YYYY年MM月DD日。
如果用原生 Date 节点,你可能需要 5 个节点。用 Code 节点 + Day.js,只需几行代码:
// 引入库
const dayjs = require('dayjs');
const relativeTime = require('dayjs/plugin/relativeTime');
require('dayjs/locale/zh-cn'); // 引入中文包
dayjs.extend(relativeTime);
// 获取输入数据
const item = $input.first();
const eventDate = item.json.eventDate;
// 核心逻辑
const now = dayjs();
const target = dayjs(eventDate);
let resultMsg;
if (target.isAfter(now)) {
const days = target.diff(now, 'day');
resultMsg = `还有 ${days} 天到期`;
} else {
const months = now.diff(target, 'month');
resultMsg = `已过期 ${months} 个月`;
}
// 输出格式化
const formattedDate = target.locale('zh-cn').format('YYYY年MM月DD日');
// 返回数据
return {
json: {
originalDate: eventDate,
readableDate: formattedDate,
status: resultMsg,
humanReadableDiff: target.from(now) // 自然语言,如 "2天前"
}
};
看到了吗?这就是代码的力量。一行 target.isAfter(now) 就解决了复杂的判断逻辑。这就是我们 N8N大学 强调的“硬核”能力。
避坑指南:时区与性能陷阱
虽然 Day.js 很好用,但在 n8n 中使用代码节点处理时间,有两个坑你必须知道,否则数据会乱套。
坑点一:服务器时区(UTC vs 本地时间)
n8n 通常运行在 Docker 容器中,默认时区是 UTC。如果你的业务逻辑依赖于“今天几点几分”,直接使用 dayjs() 获取的可能是 UTC 时间,比你本地慢 8 小时。
解决方案:
永远显式地处理时区。如果你的业务都在北京时间(Asia/Shanghai),请这样做:
const nowBeijing = dayjs().tz('Asia/Shanghai');
或者在解析输入数据时:
const target = dayjs.tz(eventDate, 'Asia/Shanghai');
坑点二:Moment.js 的体积与启动延迟
虽然 Moment.js 功能强大,但在 n8n 的 Code 节点中引入它,相比 Day.js 会有明显的加载延迟(尤其是在执行频繁的循环中)。Moment.js 是一个“庞然大物”,它会拖慢你的 Workflow 执行速度。
笔者的忠告: 除非你要做极其复杂的日历计算(比如复盘节假日排班),否则请坚持使用 Day.js。轻量化是自动化流程的第一原则。
FAQ 问答
Q1: 在 n8n 的 Code 节点里,我还能用其他的 npm 包吗?
A: 绝大多数包都可以。n8n 允许你在 Code 节点中通过 require('包名') 引入。但要注意,如果包体积过大,可能会导致执行超时。建议先在本地测试代码无误后再部署。
Q2: 如果我完全不懂 JavaScript,还能用这种方法吗?
A: 这确实是进阶玩法。但 N8N大学 的建议是:花 1 个小时学习一下 Day.js 的基础语法(如 add, subtract, format),这比你折腾 10 个 n8n 原生节点要高效得多,一劳永逸。
Q3: 为什么不推荐使用 n8n 的原生 Date 节点做任何计算?
A: Date 节点的设计初衷是“获取”和“简单格式化”。一旦涉及“差值计算”、“相对时间(如:刚刚)”、“复杂加减(如:加3个工作日)”,它的能力就捉襟见肘。使用代码节点能让你突破这个限制。
总结与资源
告别 Date 节点,拥抱 Code 节点,是 n8n 从入门到精通的分水岭。Day.js 以其轻量和强大的功能,成为了我们在 n8n 中处理时间的最佳拍档。
记住,自动化不仅仅是连接应用,更是对数据的精确掌控。善用代码,你的自动化流程将无所不能。
延伸阅读与资源:
- Day.js 官方文档:https://day.js.org/
- N8N大学:Code 节点安全编程指南(即将发布)
- n8n 官方文档:Code 节点使用说明