告别 Date 节点:使用 Day.js 或 Moment.js 在代码中进行复杂时间计算

2026-01-26 17 0

笔者按:为什么你要放弃 n8n 的 Date 节点?

大家好,我是 N8N大学 的主编。在自动化这条路上,我见过太多人被 n8n 自带的 Date 节点折磨得死去活来。它能做什么?获取当前时间、加减几天。仅此而已。

但现实世界的业务逻辑往往复杂得令人发指:“帮我找出上个月的最后一个周五”、“把这个 ISO 时间转换成‘刚刚’这种人类可读格式”、“计算两个日期之间的工作日天数”。这时候,Date 节点直接瘫痪,你不得不搭建一个丑陋的、由十几个小节点组成的逻辑链。

今天,笔者就要带你打破这个僵局。我们将深入探讨如何利用 JavaScript 生态中最强大的两个时间库——Day.jsMoment.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。现在你需要:

  1. 判断这个日期是否在未来。
  2. 如果是未来的日期,计算它距离现在还有多少天。
  3. 如果是过去的日期,计算它距离现在过去了多少个月。
  4. 最后,将结果格式化为 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 节点使用说明

相关文章

安全加固:限制 n8n Code 节点访问文件系统与内网 IP (Sandbox 配置)
超越 SQLite:为什么生产环境必须连接 PostgreSQL 以及如何配置?
元数据获取:使用 $workflow.id 和 $execution.id 生成带追踪参数的回调链接
高并发架构:配置 Redis + n8n Worker 模式实现分布式任务处理
解决 OOM 崩溃:优化 n8n 大数据量处理时的内存占用 (Memory Leak) 技巧
多入口触发:如何让一个工作流同时支持 GET/POST 甚至多个不同路径的 Webhook?

发布评论