Day.js 快速上手与 I18n 本地化实战:2kB 的 Moment.js 替代方案及西班牙语(es)Locale 的源码级解析 📅 发布时间:2026/9/18 10:08:37 👁 浏览次数: Day.js 快速上手与 I18n 本地化实战2kB 的 Moment.js 替代方案及西班牙语esLocale 的源码级解析【免费下载链接】dayjs⏰ Day.js 2kB immutable date-time library alternative to Moment.js with the same modern API项目地址: https://gitcode.com/gh_mirrors/da/dayjs本文基于 Day.js 官方西班牙语入门文档 docs/es-es/README-es-es.md 的核心骨架展开覆盖安装、核心 API解析/格式化/查询/变更、I18n 按需加载与插件扩展四大实战主题并结合 src/locale/es.js、src/index.js 等仓库源码讲清「西班牙语本地化在 Day.js 内部究竟是如何注册、回退与生效的」。读完你可以独立完成用 Day.js 替换 Moment.js 的存量代码、正确加载并使用eslocale、通过插件扩展格式化能力并理解不可变链式调用的底层实现。一、Day.js 是什么定位与核心特性官方文档对 Day.js 的定义西班牙语原文转述Day.js 是一个极简的 JavaScript 日期时间库负责解析parse、校验validate、操作manipulate和显示display日期面向现代浏览器并保持了与 Moment.js 几乎完全兼容的 API。如果你用过 Moment.js就已经会用了 Day.js。其核心特性清单如下继承自 README 文档特性说明熟悉的 API对 Moment.js 用户友好的 API 与格式 token不可变Inmutable任何变更操作都返回新实例原实例不变可链式调用Encadenable方法自由串联如startOf().add().set()国际化I18n支持按语言按需加载 locale2kB 迷你体积gzip 后约 2kB 的核心库全浏览器兼容面向所有现代浏览器「2kB 体积」并非口头宣称仓库在 package.json 中用size-limit做了硬性约束size-limit: [ { limit: 2.99 KB, path: dayjs.min.js } ]即构建产物dayjs.min.js的 gzip 体积被强制限制在 2.99KB 以内超出则构建失败。这也是「locale 与插件不进默认产物」这一设计在工程上的直接原因。一个最典型的链式用法完整体现了「解析 → 起点 → 增量 → 赋值 → 格式化」的工作流dayjs() .startOf(month) .add(1, day) .set(year, 2018) .format(YYYY-MM-DD HH:mm:ss)二、安装按照 Installation 文档 指引该文档现指向官方站点仓库内保留说明占位通过 npm 安装即可npm install dayjs --save--save参数在 npm 5 中已为默认行为命令可简写为npm install dayjs。仓库 package.json 声明了入口与类型文件main: dayjs.min.js、types: index.d.ts因此直接import dayjs from dayjs即可获得完整的 TypeScript 类型定义见 types/index.d.ts。三、核心 API解析、格式化、赋值与查询文档给出的五类基础能力示例如下覆盖了日常日期处理的绝大多数场景dayjs(2018-08-08) // 解析parse dayjs().format({YYYY} MM-DDTHH:mm:ss SSS [Z] A) // 格式化format dayjs() .set(month, 3) .month() // 取值与赋值get set dayjs().add(1, year) // 操作manipulate dayjs().isBefore(dayjs()) // 查询query3.1 解析parseDate 到底接受什么输入在 src/index.js 中parseDate是解析逻辑的入口其行为可以概括为四条规则null→ 直接构造new Date(NaN)即无效日期参数缺省 → 取当前时间new Date()Date实例 → 直接拷贝构造字符串 → 先尝试用REGEX_PARSE正则匹配匹配成功时按「本地时区」拆字段构造避免把2018-08-08误判为 UTC。正则定义在 src/constant.jsexport const REGEX_PARSE /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d)?$/可以推断该正则对分隔符做了宽松处理-、/均可甚至可省略同时兼容T与空格分隔的日期时间。此外源码中对以Z结尾的字符串!/Z$/i.test(date)跳过快速路径、直接交给原生Date解析——这类 ISO 字符串本身带时区信息交给原生引擎更稳妥。3.2 格式化token 解析与 locale 的协作format()的实现在 src/index.js关键机制有三点默认格式不传参时使用 src/constant.js 中的FORMAT_DEFAULT YYYY-MM-DDTHH:mm:ssZ占位符识别通过REGEX_FORMATsrc/constant.js匹配 token方括号内容[...]视为字面量原样输出因此文档示例中的{YYYY}里的花括号、[Z]都是字面量月份/星期名称来自 localeMMM、MMMM、dd、ddd、dddd等 token 会读取当前实例的 locale 对象this.$locale()中的months、weekdays数组。这正是 I18n 生效的位置——同一串格式 token在en与es下输出不同的月份名。源码中的取值优先级可参考getShort函数src/index.js是locale 提供的缩写/全称数组 → 若缺失则回退为英文全称截取full[index].slice(0, length)。3.3 赋值、变更与查询的不可变性保证get setset(string, int)在 src/index.js 中实现为return this.clone().$set(string, int)——先克隆再修改这就是「不可变 可链式」两个特性在源码层的直接证据。值得注意的是月份/年份的 set 做了边界保护先跳到当月 1 号再改月/年最后用Math.min(this.$D, date.daysInMonth())收敛日期避免「1 月 31 日改到 2 月」产生溢出src/index.js。manipulateadd(number, units)src/index.js对月/年单位走set通道处理了 2/31 日这类跨月边界对天/小时/分钟/秒则按毫秒步长累加subtract只是add(number * -1)的别名。queryisBefore的实现是this.endOf(units) dayjs(that)src/index.jsisAfter对称使用startOf。units缺省时比较到毫秒级。四、I18n从「按需加载」到 es locale 的完整内部机制这是文档中与es-es这一语言目录强相关的核心章节。官方示例import dayjs/locale/es // 按需加载carga bajo demanda dayjs.locale(es) // 全局使用西班牙语区域设置 dayjs(2018-05-05) .locale(zh-cn) .format() // 在具体实例上改用简体中文三点关键语义locale 不会进入默认构建产物配合 size-limit 约束实现 2kBdayjs.locale(es)是全局切换实例级.locale(...)只影响该实例且同样遵循不可变原则。4.1 加载即注册src/locale/es.js 做了什么docs/es-es/README-es-es.md 中import dayjs/locale/es对应仓库文件 src/locale/es.js。该文件定义了完整的西班牙语 locale 对象并在模块加载末尾执行注册const locale { name: es, monthsShort: ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic.split(_), weekdays: domingo_lunes_martes_miércoles_jueves_viernes_sábado.split(_), weekdaysShort: dom._lun._mar._mié._jue._vie._sáb..split(_), weekdaysMin: do_lu_ma_mi_ju_vi_sá.split(_), months: enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre.split(_), weekStart: 1, formats: { LT: H:mm, LTS: H:mm:ss, L: DD/MM/YYYY, LL: D [de] MMMM [de] YYYY, LLL: D [de] MMMM [de] YYYY H:mm, LLLL: dddd, D [de] MMMM [de] YYYY H:mm }, relativeTime: { future: en %s, past: hace %s, s: unos segundos, m: un minuto, mm: %d minutos, h: una hora, hh: %d horas, d: un día, dd: %d días, M: un mes, MM: %d meses, y: un año, yy: %d años }, ordinal: n ${n}º } dayjs.locale(locale, null, true) // 第三个参数 true仅注册不改变全局 locale export default locale几个值得注意的细节weekStart: 1西班牙语习惯以周一为一周起点。在startOf(week)的源码中src/index.jsthis.$locale().weekStart被直接用于计算周界因此切到eslocale 后「本周起始日」的行为会自动从周日变为周一formats六件套LDD/MM/YYYY与英语 locale 的MM/DD/YYYY不同说明西班牙语日期显示为「日/月/年」LL等长格式通过[de]字面量占位符表达「D de MMMM de YYYY」的自然语言句式。这些预设格式供localizedFormat插件消费ordinal: n ${n}º西班牙语序数词为数字后加º如8º供advancedFormat插件的Dotoken 调用relativeTime完整的 13 个键future/past/s/m/mm/h/hh/d/dd/M/MM/y/yy供relativeTime插件生成「hace 3 días」「en 2 meses」这类自然时间。测试用例 test/locale/keys.test.js 强制校验每个 locale 的relativeTime必须恰好包含这 13 个键保证跨语言一致性dayjs.locale(locale, null, true)第三个参数true表示「仅注册到全局 locale 表不切换全局默认」保证业务代码显式调用dayjs.locale(es)之前行为不被破坏。locale 结构规范同样由测试守护test/locale/keys.test.js 遍历src/locale目录全部 140 个 locale 文件校验name与文件名一致且小写、weekdays为数组、formats必须含L/LL/LLL/LLLL/LT/LTS且不得含额外键、ordinal对 1–31 天均可输出等。4.2 名称回退es-es如何落到esdocs/es-es/ 目录本身以es-es西班牙本土西班牙语命名而 locale 注册名是es。这背后是parseLocale的回退机制src/index.jsconst parseLocale (preset, object, isLocal) { // ... if (typeof preset string) { const presetLower preset.toLowerCase() if (Ls[presetLower]) { l presetLower } if (object) { Ls[presetLower] object; l presetLower } const presetSplit preset.split(-) if (!l presetSplit.length 1) { return parseLocale(presetSplit[0]) // es-es 未注册 → 递归尝试 es } } // ... }逻辑是先查精确名称统一转小写若未命中且名称带连字符则递归尝试前缀es-es→es。因此dayjs.locale(ES-ES)、dayjs.locale(es-es)最终都会命中eslocale。而dayjs(...).locale(zh-cn)这种实例级调用走Dayjs.locale()方法src/index.js它克隆实例后设置$L字段原实例不受影响。全局层面dayjs.locale直接就是parseLocale本身src/index.js全局默认 locale 初始为en且enlocale 在核心源码中内置src/index.js无需任何 import。五、插件ComplementosadvancedFormat 示例与扩展机制文档对插件的定义是「插件是一个独立模块可以添加到 Day.js 上以扩展功能或增加新特性」。官方示例import advancedFormat from dayjs/plugin/advancedFormat // 按需加载 dayjs.extend(advancedFormat) // 使用插件 dayjs().format(Q Do k kk X x) // 现在可以使用更多格式5.1 extend 的「只安装一次」语义dayjs.extend的实现在 src/index.jsdayjs.extend (plugin, option) { if (!plugin.$i) { // 每个插件只安装一次 plugin(option, Dayjs, dayjs) plugin.$i true } return dayjs }约定插件是一个函数接收(option, Dayjs, dayjs)三个参数$i标记保证重复extend是幂等的。注意示例中没有import dayjs from dayjs一行也能工作的前提——示例是接在完整上下文之后展示的独立使用时需先引入 dayjs 本体。5.2 advancedFormat 插件Q、Do、k、X 从哪来docs/es-es/README-es-es.md 示例中的Q Do k kk X x其 token 支持在 src/plugin/advancedFormat/index.js 中全部可以找到。该插件通过重写proto.format的方式工作先用自己的正则/\[([^\]])]|Q|wo|ww|w|WW|W|zzz|z|gggg|GGGG|Do|X|x|k{1,2}|S/gsrc/plugin/advancedFormat/index.js替换扩展 token再调用被保存下来的原format处理剩余的标准 tokenToken含义源码实现Q季度1–4Math.ceil((this.$M 1) / 3)Do序数词日期依赖 locale 的 ordinallocale.ordinal(this.$D)即西班牙语下输出8ºw / ww本地周数受 weekStart 影响this.week()W / WWISO 周数this.isoWeek()k / kk24 制小时0 点表示为 24this.$H 0 ? 24 : this.$HX/x秒级 / 毫秒级 Unix 时间戳Math.floor(time / 1000)/getTime()gggg / GGGG本地周年起 / ISO 周年起this.weekYear()/this.isoWeekYear()z / zzz时区缩写 / 全称this.offsetName()需 timezone 插件支持这里可以看到 I18n 与插件的协同Do直接读取locale.ordinal在eslocale 下得到1º–31º在enlocale 下得到1st–31st。仓库 src/plugin/ 目录共提供 37 个官方插件advancedFormat、relativeTime、utc、duration、timezone、customParseFormat等每个插件均配有独立类型定义types/plugin/与测试test/plugin/。其中relativeTime插件正是 src/locale/es.js 中relativeTime字段的消费者。六、工程质量与适用边界结合仓库配置可以确认几条适用于本文所述功能的工程事实测试策略package.json 的test脚本在Pacific/Auckland、Europe/London、America/Whitehorse三个不同时区环境下分别运行且 jest 配置要求src目录100% 行覆盖率--coverageThresholdlocale 结构由 test/locale/keys.test.js 全量守护体积约束size-limit硬上限 2.99KBgzip配合「locale/插件按需引入」的设计达成 README 宣称的 2kB 级别体积许可协议MITLICENSE文档中亦明确「Day.js 以 MIT License 授权」。适用边界方面需要注意本文所有行为描述以当前仓库源码为准。基础format不支持Q/Do/k/X等扩展 token需 advancedFormat 插件相对时间、LL系列格式的实际消费方分别是relativeTime与localizedFormat插件z/zzztoken 依赖 timezone 插件提供的offsetName。此外核心解析基于原生Date与宽松正则复杂的任意格式解析属于customParseFormat插件的能力范围。七、小结以 docs/es-es/README-es-es.md 为主线本文完成了从「文档级用法」到「源码级机制」的闭环安装npm install dayjs默认产物内置enlocale体积受 2.99KB 硬约束五大 API解析/格式化/getset/操作/查询全部以「克隆后再修改」实现不可变性set对月/年做了跨月边界收敛I18nimport dayjs/locale/es触发dayjs.locale(locale, null, true)的静默注册parseLocale提供es-es → es的名称回退eslocale 携带weekStart: 1、DD/MM/YYYY日期格式、º序数词与 13 键相对时间模板插件dayjs.extend幂等安装advancedFormat以「先替换扩展 token、再委托原 format」的装饰器模式扩展格式能力且与 locale 的ordinal深度协作。对于从 Moment.js 迁移的团队这套「核心 API 同名同形 扩展能力按需插件化」的设计正是其 API 兼容性承诺在实现层面的来源。【免费下载链接】dayjs⏰ Day.js 2kB immutable date-time library alternative to Moment.js with the same modern API项目地址: https://gitcode.com/gh_mirrors/da/dayjs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考