date-fns 入门指南:在浏览器与 Node.js 中优雅地操作 JavaScript 日期
2026/9/19 21:22:39 网站建设 项目流程

date-fns 入门指南:在浏览器与 Node.js 中优雅地操作 JavaScript 日期

【免费下载链接】date-fns⏳ Modern JavaScript date utility library ⌛️项目地址: https://gitcode.com/gh_mirrors/da/date-fns

date-fns 是一个现代、模块化的 JavaScript 日期工具库,为在浏览器与 Node.js 中处理日期提供全面、简洁且一致的工具集。本文基于 date-fns 仓库(当前核心包版本为 v4.4.0)的官方文档与源码,讲解它的核心设计理念、安装方式、子模块体系以及最常用的函数用法,读完即可在项目中快速上手。仓库核心文档与源码可分别参考 pkgs/core/docs/gettingStarted.md 与 pkgs/core/src。

为什么选择 date-fns

date-fns 的定位是“日期领域的 Lodash”,它在不引入复杂抽象的前提下,把日常开发中几乎所有与日期相关的操作都封装成了简单、一致的函数。从仓库根目录 README.md 的定位描述看,它的核心卖点集中在以下几点:

  • 200+ 函数覆盖各种场景:从加减日期、比较日期、格式化输出,到区间遍历、周/年历计算、时区处理,几乎覆盖所有日常需求。
  • 模块化设计:只引入你需要的那部分代码,天然兼容 webpack、Browserify、Rollup 等打包工具,并且支持 tree-shaking,避免把整个库塞进最终产物。
  • 原生 Date 类型:直接基于 JavaScript 现有的原生Date类型工作,出于安全考虑不去扩展核心对象(不污染原型链)。
  • 不可变与纯函数:所有函数都是纯函数,总是返回一个新的 Date 实例,绝不修改传入的参数,便于预测行为与测试。
  • 100% TypeScript:整个库由 TypeScript 编写,并附带全新手工打磨的类型定义,开箱即用的类型安全。
  • I18n 国际化:内置数十种语言 locale,按需引入,只打包你需要的语言。

需要特别说明的是:这里的“200+ 函数”是官方文档的表述,实际数量以发布版本为准;从 pkgs/core/package.json 的exports字段可以看到,当前仓库为每个函数都提供了独立的子路径导出。

安装与快速上手

date-fns 以 npm 包形式发布。官方文档给出的安装命令如下:

npm install date-fns --save # 或 yarn add date-fns

以 npm 安装为例,仓库中pkgs/core就是实际的发布包(包名为date-fns,见 pkgs/core/package.json)。安装完成后即可按需导入:

import { compareAsc, format } from "date-fns"; format(new Date(2014, 1, 11), "yyyy-MM-dd"); //=> '2014-02-11' const dates = [ new Date(1995, 6, 2), new Date(1987, 1, 11), new Date(1989, 6, 10), ]; dates.sort(compareAsc); //=> [ // Wed Feb 11 1987 00:00:00, // Mon Jul 10 1989 00:00:00, // Sun Jul 02 1995 00:00:00 // ]

上面的示例同时演示了两个最常用的函数:

  • format(date, formatString):按指定的格式字符串输出日期;
  • compareAsc(dateLeft, dateRight):比较两个日期,可作为Array.prototype.sort的比较器直接传入,实现日期数组的升序排序。

从 pkgs/core/src/compareAsc/index.ts 的实现可以看到compareAsc的内部逻辑非常直观:它先把两个入参统一转换成时间戳做差,差值为负返回-1、为正返回1、相等返回0(若差值为NaN则原样返回NaN)。该行为在 pkgs/core/src/compareAsc/test.ts 中有完整的测试覆盖,包括相等、早于、晚于以及数组排序四种典型场景。

另一个文档中的经典示例是相对时间格式化:

import { formatDistance, subDays } from "date-fns"; formatDistance(subDays(new Date(), 3), new Date(), { addSuffix: true }); //=> "3 days ago"

这里subDays从当前时间减去 3 天,formatDistance计算两个日期之间的友好距离描述,addSuffix: true会在结果后追加“ago”等前后缀。值得一提的是,这类描述会根据所选 locale 输出不同语言(详见下文“国际化”一节)。

关于输入参数的类型

date-fns 的绝大多数函数都接受“可被转换为 Date 的值”(DateArg)作为输入:既可以是 Date 实例,也可以是时间戳数字。所有传入的参数都会先经过内部统一的toDate转换。从 pkgs/core/src/toDate/index.ts 的实现可以看到,toDate通过constructFrom完成转换:Date 实例会被克隆,数字被当作时间戳处理,其余类型得到 Invalid Date。这也从源码层面印证了“不可变、纯函数”的设计——输入参数永远不会被修改。

子模块:FP 函数式编程变体

date-fns 的 npm 包内还附带了一些可选功能子模块。根据 pkgs/core/docs/gettingStarted.md 的说明,目前主要包括:

  • FP—— 面向函数式编程的函数变体,参见 pkgs/core/src/fp 目录。

子模块是嵌套包含的:如果你想同时使用多个子模块功能,后列的子模块已被包含在前者之中。使用子模块前同样需要先安装 npm 包,然后从对应子路径导入:

// 主模块:标准用法 import { addDays } from "date-fns"; // FP 变体:柯里化、参数顺序更贴合函数式组合 import { addDays, format } from "date-fns/fp";

从 pkgs/core/package.json 的exports可以看出,FP 子模块为几乎每个函数都提供了两种变体:标准版(如./fp/addDays)和带WithOptions后缀、可传入 options 的版本(如./fp/addDaysWithOptions)。相应地,pkgs/core/src/fp/index.ts 是这些导出的汇总入口。

核心 API 速览:format 与 unicode 令牌

format是 date-fns 使用频率最高的函数之一,它的格式字符串基于Unicode Technical Standard #35(CLDR 日期字段符号表),而不是 Moment.js 的自定义规则。所有支持的令牌在 pkgs/core/src/format/index.ts 的文档注释中有完整表格,以下列出最常用的一部分:

单元令牌结果示例说明
日历年份y/yy/yyyy44/44/0044四位年份建议用yyyy
月份M/MM/MMM/MMMM1/01/Jan/JanuaryMMMM为完整月份名
日(月内)d/dd1/01D(年内第几天)区分
日(年内)D/DD/DDD1/01/001useAdditionalDayOfYearTokens选项
星期几E..EEE/EEEE/EEEEEMon/Monday/M
小时 [0-23]H/HH0/0024 小时制
小时 [1-12]h/hh1/0112 小时制,常与a连用
AM/PMa..aa/aaa/aaaaAM/am/a.m.
分钟m/mm0/00
s/ss0/00

注意format的令牌与 Moment.js 等库不同,例如:

  • D/DD表示“年内第几天”(1, 2, ..., 365, 366),常被误当作“月内第几天”;月内第几天应使用d/dd(1, 2, ..., 31)。
  • YY/YYYY表示“本地周编号年份”(44, 01, 00, 17),常被误当作日历年份;日历年份应使用yy/yyyy

为防止这种混淆,formatparse默认会拒绝DDDYYYYYY四个令牌,除非显式传入对应选项(详见 pkgs/core/docs/unicodeTokens.md):

// ❌ 错误:把 YYYY/DD 当成年月日用 format(new Date(), "YYYY-MM-DD"); // ✅ 正确 format(new Date(), "yyyy-MM-dd"); //=> '2018-10-10' // ✅ 显式启用额外令牌 format(new Date(), "D", { useAdditionalDayOfYearTokens: true }); //=> '283' parse("365+1987", "DD+YYYY", new Date(), { useAdditionalDayOfYearTokens: true, useAdditionalWeekYearTokens: true, }); //=> 'Wed Dec 31 1986 ...'

此外,格式字符串中被单引号'...'包裹的字符会被当作字面量原样输出,两个连续单引号''表示一个真正的单引号字符。

format 的底层实现

从 pkgs/core/src/format/index.ts 可以看到,格式化字符串首先被拆解为两部分正则:formattingTokensRegExp匹配yYQqMLwIdDecihHKkms等字母加o构成的序数令牌、连续的相同字母序列以及引号转义段;longFormattingTokensRegExp则负责P/p开头的长格式令牌(如PPPP)。随后每个令牌交由_lib/format/formatters下的对应格式化器逐个渲染。对format的内部机制感兴趣的读者,可以继续阅读 pkgs/core/src/_lib/format 目录。

国际化(I18n)与按需引入 locale

date-fns 内置数十种语言 locale。从 pkgs/core/package.json 的exports可以看到按语言代码划分的独立子路径导出(如./locale/zh-CN./locale/en-US./locale/ja等),每个 locale 均位于 pkgs/core/src/locale 目录。以简体中文为例:

import { format, formatDistance } from "date-fns"; import { zhCN } from "date-fns/locale"; format(new Date(2024, 0, 1), "EEEE MMMM d, yyyy", { locale: zhCN }); // 输出中文星期与月份 formatDistance(subDays(new Date(), 3), new Date(), { locale: zhCN, addSuffix: true });

每个 locale 都是一个符合统一Locale接口的对象。从 pkgs/core/src/locale/zh-CN/index.ts 的实现可以看到,zhCN包含codeformatDistanceformatLongformatRelativelocalizematch六个成员,并通过options.weekStartsOn: 1(周一为一周起点)与options.firstWeekContainsDate: 4声明该语言环境的周历规则。这些选项会直接影响依赖周历计算的函数(如startOfWeekgetWeekformat中的w/E等令牌)的结果。locale 的完整结构定义见 pkgs/core/src/locale/types.ts(位于 pkgs/core/src/locale 目录内)。

由于每个 locale 都是独立子路径导出,打包器可以轻松做 tree-shaking,最终产物只包含实际用到的语言,这也是“Include only what you need”理念的体现。

进阶阅读:更多函数与官方文档

本文只覆盖了入门必需的部分。date-fns 的函数体系非常庞大,按用途大致可分为几类:

  • 运算类addDayssubMonthsaddBusinessDays等加减操作;
  • 比较类compareAscisAfterisEqualisSameDay等;
  • 区间类eachDayOfIntervalareIntervalsOverlappingintervalToDuration等;
  • 取值/设值类getYearsetMonthstartOfWeekendOfDay等;
  • 解析类parseparseISOfromUnixTime等;
  • 单位换算类hoursToMinutesdaysToWeeksyearsToMonths等。

所有这些函数都遵循同样的设计哲学:纯函数、不修改入参、类型安全、按需导入。仓库内每个函数目录都包含index.ts(实现)与test.ts(vitest 测试),例如 pkgs/core/src/compareAsc 目录,方便开发者阅读实现细节与行为契约。

结语

date-fns 用一套简单、一致、类型安全的函数,把 JavaScript 日期操作的复杂度封装了起来:安装只需一条 npm 命令,使用遵循“按需导入 + 原生 Date + 纯函数”的现代实践,国际化与 FP 变体则让它能适配更多工程场景。希望本文能帮你快速建立起对 date-fns 的整体认知,并在自己的项目中得心应手地使用它。

【免费下载链接】date-fns⏳ Modern JavaScript date utility library ⌛️项目地址: https://gitcode.com/gh_mirrors/da/date-fns

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询