停止在 JavaScript 中错误计算年龄:闰年、2 月 29 日和 1 月 31 日陷阱
发布: (2026年2月9日 GMT+8 09:18)
3 分钟阅读
原文: Dev.to
Source: Dev.to
大多数年龄计算器都算错了
- 它们只做
nowYear - dobYear,却忘记检查生日是否已经过去。 - 它们把所有月份都当成同等长度。
- 它们在 2 月 29 日生日上崩溃。
- 它们会遇到 JavaScript 的 “1 月 31 日 + 1 个月 = 3 月” 的意外。
如果你需要一个可以直接使用的年龄计算器,就必须正确处理这些边缘情况。
我们真正想要计算的内容
给定
dob– 出生日期asOf– 你想要测量年龄的日期(默认是今天)
我们想要
- years – 已经完整度过的生日数
- months – 自上一次生日起完整的月份数
- days – 自该月份锚点起剩余的天数
如果 asOf = dob);
// ---- Years ----
let years = asOf.getFullYear() - dob.getFullYear();
const bdayThisYear = birthdayInYear(dob, asOf.getFullYear(), "FEB_28");
if (asOf {
it("handles birthday not yet happened this year", () => {
const dob = new Date("2000-10-20");
const asOf = new Date("2026-02-09");
const r = calculateAge(dob, asOf);
expect(r.years).toBe(25);
});
it("handles month‑end clamping (Jan 31)", () => {
const dob = new Date("2000-01-31");
const asOf = new Date("2000-03-01");
const r = calculateAge(dob, asOf);
// If your month add is buggy, this often breaks.
expect(r.years).toBe(0);
expect(r.months).toBeGreaterThanOrEqual(1);
});
it("handles Feb 29 birthdays with FEB_28 rule", () => {
const dob = new Date("2004-02-29");
const asOf = new Date("2025-02-28");
const r = calculateAge(dob, asOf);
// Under FEB_28 policy, birthday is considered reached on Feb 28.
expect(r.years).toBe(21);
});
it("rejects asOf before dob", () => {
const dob = new Date("2020-01-01");
const asOf = new Date("2019-12-31");
expect(() => calculateAge(dob, asOf)).toThrow();
});
});
你可以添加的其他边缘案例
dob = 1999-12-31,asOf = 2000-01-01dob = 2000-02-28,asOf = 2001-02-28dob = 2000-03-31,asOf = 2000-04-30
关键要点
要得到正确的年龄输出:
- 规范化 为仅日期(午夜)。
- 定义 一个统一的 2 月 29 日政策。
- 在跨月时 对月末进行夹取(clamp)。
- 编写 覆盖这些奇怪日期的测试。
就这么简单——不需要外部库。
演示(可选):