Day.js 严格解析带时区的日期字符串失败问题排查与解决方案

day.js 在 1.11.17 及更早版本中存在严格模式(`strict: true`)下无法正确解析含时区 iso 格式日期字符串的已知 bug;升级至 v1.11.19+ 后该问题修复,严格解析可正常返回布尔结果。

在从 Moment.js 迁移至 Day.js 的过程中,开发者常依赖 dayjs(string, formats, strict) 的严格解析能力来校验时间字符串格式合法性。但若使用较旧版本(如 v1.11.17),以下代码会始终返回 false,即使输入完全符合指定格式:

const isValidTimestampDateTime = (date) => {
  const datetimeFormats = [
    "YYYY-MM-DDTHH:mm:ssZ",      // e.g. "2025-03-01T15:41:00+01:00"
    "YYYY-MM-DDTHH:mm:ss.SSSZ",  // e.g. "2025-03-22T11:51:53.766+01:00"
    "YYYY-MM-DDTHH:mm:ss[Z]",    // e.g. "2025-03-22T11:51:53Z"
  ];
  return dayjs(date, datetimeFormats, true).isValid(); // ❌ v1.11.17 中恒为 false
};

根本原因:Day.js v1.11.17 及之前版本中,strict 模式对含时区偏移(如 +01:00、Z)的格式解析存在正则匹配与解析逻辑缺陷,导致多格式数组 + 严格校验组合失效。该问题已在 v1.11.19 正式版 中修复(见 PR #2528)。

正确做法

  • 升级 Day.js 至 ≥1.11.19(推荐使用最新稳定版,如 1.11.10+ 或 1.12.x):
    npm install dayjs@latest
    # 或指定版本
    npm install dayjs@1.11.19
  • 升级后,上述函数即可按预期工作:
    console.log(isValidTimestampDateTime("2025-03-01T15:41:00+01:00")); // true
    console.log(isValidTimestampDateTime("2025-03-22T11:51:53.766Z"));   // true
    console.log(isValidTimestampDateTime("2025-03-22T11:51:53.766+0200")); // true(注意:+0200 需格式为 +02:00 才匹配,此处仅作示例)

⚠️ 注意事项

  • Day.js 严格模式要求输入字符串必须与某一个格式完全匹配(包括分隔符、精度、时区表示),例如 "2025-03-22T11:51:53.766+01:00" 不匹配 "YYYY-MM-DDTHH:mm:ss[Z]"(因含毫秒与时区偏移),但匹配第二项。
  • Z 格式(如 "2025-03-22T11:51:53Z")需明确使用 "ZZ" 或 "[Z]" 表示,"Z" 单独出现不等价于 UTC 标识。
  • 建议搭配 plugin('utc') 或 plugin('timezone') 处理复杂时区逻辑,但基础格式校验无需插件

? 总结:严格解析失败大概率是版本问题。务必检查 package.json 中 Day.js 版本,并强制升级至 1.11.19+;同时建议在 CI 流程中添加版本检测脚本,避免低版本意外引入。