做考勤、做账期、做会员到期提醒,都躲不开「根据某个时间推算日期」。看起来简单,实际动手时总有几个地方会出错,尤其是月底和闰年。
场景一:加 N 天
最基础的需求,比如「7 天后提醒」。别自己用 24 小时乘天数去加时间戳,遇到夏令时或者时区切换会偏一小时。用日期库的加法函数:
// JS
const d = new Date('2026-01-31');
d.setDate(d.getDate() + 7);
# Python
from datetime import date, timedelta
(date(2026,1,31) + timedelta(days=7))这些函数会自动处理跨月、跨年、闰年,不用自己判断二月有几天。
场景二:加 N 个月
这个坑最多。1 月 31 日加一个月,2 月没有 31 号,结果是什么?不同库的处理不一样:有的返回 2 月 28 日,有的直接抛异常,有的滚到 3 月 3 日。
Java 的 LocalDate.plusMonths 会把结果收敛到月末,也就是 2 月 28 日。MySQL 的 DATE_ADD('2026-01-31', INTERVAL 1 MONTH) 返回 2026-02-28。而有些语言的时间戳算法会溢出到下个月。
做账期、订阅续费这类业务,必须明确约定规则,并且写测试用例覆盖 1 月 31 日、3 月 31 日、闰年 2 月 29 日这几种边界。
场景三:算两个日期差多少天
不要用时间戳相减再除以 86400,因为时区偏移和夏令时会让结果出现 0.96 天这种小数。正确做法是转成日期对象再求差:
const a = new Date('2026-03-01');
const b = new Date('2026-01-31');
Math.round((a - b) / 86400000); // 30先归零到当天 0 点再相减,结果才稳定。Python 里直接用 date 对象相减,得到的是 timedelta,取 .days 即可。
场景四:按周推算
「本周一」「下周一」这种需求,关键在周起始日的定义。中国习惯周一为一周开始,而 JS 的 getDay() 里周日是 0,写起来容易错一位。
稳妥的写法是先算出当前是周几,再减去偏移量,最后归零时间部分。跨年那周也要测,12 月 31 日可能是周一也可能是周日。
场景五:工作日推算
「5 个工作日之后」不能直接加 5 天,要跳过周末和法定节假日。周末好判断,节假日只能查表。建议维护一张节假日表,循环推进,遇到非工作日就跳过,直到累计满 N 个工作日。最后提醒一句:所有涉及日期的逻辑,都要明确用哪个时区。服务器在 UTC、用户在 UTC+8,跨零点时「今天」是哪天会直接导致判断错误。