· ARTICLE · 2025.01.01 · 3 MIN ·
2024 年最后一天被显示为 2025?Angular DatePipe 显示年份错误
2024 年最后一天被显示为 2025?Angular DatePipe 显示年份错误 · by fancyoung
AI · HERO seed:3120250101 2024 年最后一天被显示为 2025?Angular DatePipe 显示年份错误
在 2024 年的最后一天(12 月 31 日),我遇到了一个奇怪的问题: 前端页面所有时间显示都增加了 1 年。
问题描述
代码如下:
<td [nzAlign]="'center'">{{ data.createdAt | date : 'YYYY-MM-dd HH:mm' }}</td>
data.createdAt 是一个日期时间字段,期望格式化为 YYYY-MM-dd HH:mm,但在运行时,所有 2024 年的日期被错误显示为 2025 年。
原因分析
1. 格式化字符串的问题
Angular 的 DatePipe 使用的是 标准日期格式化规则,其中:
- `YYYY:常被误认为是表示年份的占位符,但实际上这是错误的。
- 正确的占位符是:
yyyy。
YYYY 在某些日期库(如 Moment.js)中表示 “ISO 年”,与普通公历年份(yyyy)不同:
YYYY表示与某些周数相关联的年份。yyyy表示普通的公历年份。
示例:
2024-12-31使用YYYY格式化可能会显示为 2025,因为它属于 ISO 年 2025 的第一周。
2. ISO 年的影响
ISO周日历系统是ISO 8601日期和时间标准的一部分,是一种闰周历系统。这个系统主要用在政府和商务的会计年度,用以维持时序。这个系统依据格里历的年度中特定的一个周日,决定该年是否要增加一个星期。
ISO 年的使用:
- ISO 年(YYYY) 一般不会与普通的 “月” 和 “日”(MM 和 DD)结合使用,因为 ISO 年是基于周的
- ISO 年主要和 ISO 周(Www) 一起使用,用于表示基于周的日期
- 主要用于财务、时间表管理、统计分析等需要基于周的场景
ISO 年和普通公历年份的不同点是:
- ISO 年以每年的第一周为基准。
- 某些日期(如 12 月 31 日)可能会被归入下一年的 ISO 年。
为什么只在 12 月 31 日出现问题,且之前几年都正常?
ISO 周年(YYYY)基于周的划分规则,它规定:
- 一年的第一周是包含 1 月 4 日的那一周。
- 如果 12 月 31 日所在的那一周属于下一年的 ISO 周,则 YYYY 会显示为下一年的年份。
因此:
- 2024 年的 12 月 31 日 是 2025 年的第一周,所以 YYYY 会显示为 2025。
- 2023 年的 12 月 31 日 是 2023 年的最后一周,所以 YYYY 正常显示为 2023。
- 2022 年的 12 月 31 日 是 2022 年的最后一周,所以 YYYY 正常显示为 2022。
注:实际 2024 年的 12 月 30 日 时已经出问题了,会被显示成 2025-12-30,当天可能数据不多被忽略了。
解决方法
1. 修改格式化字符串
将 YYYY 替换为 yyyy,确保 DatePipe 使用普通的公历年份格式化。
修改后的代码如下:
<td [nzAlign]="'center'">{{ data.createdAt | date : 'yyyy-MM-dd HH:mm' }}</td>
2. 当于 Moment.js 或 day.js 混用
当批量替换代码时,发现有些地方用了 day.js,有些地方用的是 angular 的 DatePipe。不能统一使用 yyyy 格式化。
此时通过完整的日期格式来替换即可。区别在于:
- angular:
yyyy-MM-dd表示公历年份日期。 - day.js:
YYYY-MM-DD表示公历年份日期。
总结
在 AngularJS 中:
- 使用
YYYY时,年份会基于 ISO 周年的规则,导致某些日期(例如 12 月 31 日)可能显示为下一年的年份。 - 使用
yyyy时,年份总是基于普通的公历年份,不会出现这种问题。 - 解决方法:修改格式化字符串, 批量搜索
YYYY-MM-dd替换为yyyy-MM-dd。
如果您不希望受到 ISO 周年的影响,务必使用 yyyy 来显示年份。