time.add 是纳秒级偏移,不处理日历逻辑,跨夏令时可能偏差;time.adddate 才是日历加减,自动处理闰年、月末等,二者语义完全不同。

time.Add 是纳秒偏移,不是“加一天”
它只做底层时间戳加减,不理解日历逻辑。比如 t.Add(24 * time.Hour) 确实加了 86400 秒,但若跨夏令时切换(如美国 PDT → PST),这 24 小时可能对应物理上的 23 或 25 小时,导致“同时间点”错位。
常见错误现象:2023-11-05 01:30 -0700 PDT 加 24 * time.Hour 后变成 2023-11-06 01:30 -0800 PST —— 表面看是“第二天同一时刻”,实际间隔是 25 小时。
- 适合场景:超时控制、倒计时、日志微调等需要精确纳秒间隔的场合
- 不适合场景:账单周期、生日提醒、报表截止日等依赖日历语义的业务
- 参数必须是
time.Duration;不能直接乘 float64,比如time.Hour * 7.5会编译失败
time.AddDate 才是真正的“日历加减”
AddDate(0, 0, 1) 表示“日历上加 1 天”,自动处理月末、闰年、大小月。它不依赖固定秒数,而是按年/月/日字段重组时间,再标准化。
典型问题:10 月 31 日调用 AddDate(0, 1, 0) 得到的是 12 月 1 日,不是 11 月 30 日——因为 11 月没有 31 日,系统归一化为“11 月 31 日 → 12 月 1 日”。这不是 bug,是设计行为。
- 参数只能是 int:年、月、日三个整数,不支持小时/分钟
- 负值合法:
AddDate(0, -1, 0)可回退一个月,AddDate(0, 0, -7)表示 7 天前 - 想取“本月最后一天”?别用
AddDate(0, 1, -1),正确写法是:time.Date(t.Year(), t.Month()+1, 1, 0, 0, 0, 0, t.Location()).AddDate(0, 0, -1)
时区没设对,Add 和 AddDate 都会出错
这两个方法本身不改时区,只在输入时间的 Location 下运算。如果解析字符串没指定时区,time.Parse("2006-01-02", "2024-03-10") 在本地时区下可能把 3 月 10 日当成 EST(实际已是 EDT),结果偏差一小时。
- 建议:业务时间统一用
time.UTC运算,显示时再转本地时区 -
time.Now()返回本地时区,如需稳定计算,先转.UTC() - 加载自定义时区要用
time.LoadLocation,注意系统时区数据库版本影响夏令时判断
别混用 Duration 和日历单位
这是线上时间漂移最常被忽略的点。24 * time.Hour 是固定秒数,AddDate(0, 0, 1) 是日历概念,二者语义完全不同。
- 定时任务按“每天上午 9 点”运行?必须用
AddDate或重构time.Date,否则夏令时切换日可能漏跑或重复跑 - 计算“过去 7 天”的起始时间?用
t.AddDate(0, 0, -7)安全;用t.Add(-7 * 24 * time.Hour)在 DST 切换日可能偏差 1 小时 -
time.Since(t)返回Duration,不能直接和7 * 24 * time.Hour比较来判断“是否超过 7 天”——除非你明确要按固定秒数算
真正难的不是写对某一行代码,而是每次加减前,先问自己一句:我要的是物理时长,还是日历日期?选错就埋雷。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











