Go 的 time.Time 不可变,加减操作返回新值;应使用 Add/Sub 处理时钟偏移,AddDate 处理日历运算,避免手动修改字段或混淆 Duration 与日历单位。

Go 的 time.Time 本身不可变,所有加减操作都返回新值,不是原地修改 —— 这是绝大多数时间计算出错的根源。
用 Add 和 Sub 而不是手动改字段
别碰 Time.Year、Time.Month 这类字段:它们只是快照,改了也没用,且跨月/闰年时逻辑完全失效。
Add 接收 time.Duration,适合秒级、分钟级、小时级偏移;Sub 返回两个时间点的差(Duration)。
-
t.Add(24 * time.Hour)是“加一天”,不是“加 24 小时”——它会考虑夏令时切换(比如某天实际是 23 或 25 小时) - 要严格加 24 小时,用
t.Add(24 * time.Hour)没问题;但要加“日历上的一天”,得用time.Date构造新时间(见下节) -
t1.Sub(t2)结果是Duration,注意负值:如果t1更早,结果为负
跨日/跨月必须用 time.Date 重构
因为 Add(72 * time.Hour) 和 “加三天”在夏令时边界可能不等价;而 AddDate(0, 0, 3) 才真正按日历算。
立即学习“go语言免费学习笔记(深入)”;
-
t.AddDate(0, 0, 1):加 1 天(自动处理 31→1、28/29→1 等) -
t.AddDate(0, 1, 0):加 1 个月(如 1 月 31 日 → 2 月 28 日或 29 日) -
t.AddDate(1, 0, 0):加 1 年(同样自动适配闰年) - 想“本月最后一天”,不能
AddDate(0,1,-1),应先到下月 1 号再减 1 天:time.Date(t.Year(), t.Month()+1, 1, 0, 0, 0, 0, t.Location()).AddDate(0,0,-1)
注意 time.Location 对加减的影响
同一个 time.Time 值,在不同时区下 Add 的表现一致(底层纳秒偏移不变),但 AddDate 和显示结果受时区影响。
- 本地时区(
time.Local)下AddDate(0,0,1)可能跨 DST 切换,导致当天时长异常 - UTC 下最稳定:
t.UTC().AddDate(0,0,1)不受夏令时干扰 - 解析字符串后默认是本地时区,常被忽略:
time.Parse("2006-01-02", "2024-03-10")在美国东部是EST,但 3 月 10 日已是EDT—— 建议显式用time.UTC或指定 location
常见错误:混淆 Duration 和日历单位
24 * time.Hour 是固定 86400 秒,AddDate(0,0,1) 是日历上的“一天”,二者语义不同,选错会导致线上时间漂移。
- 定时任务按“每天上午 9 点”运行?用
AddDate或重新构造time.Date,别用Add(24*time.Hour) - 计算“过去 7 天”的起始时间?
t.AddDate(0,0,-7)安全;t.Add(-7*24*time.Hour)在夏令时切换日可能偏差 1 小时 -
time.Since(t)返回Duration,不能直接和7*24*time.Hour比较来判断“是否超过 7 天”——除非你明确要按固定秒数算
日历运算和时钟运算的分界线很细,一不留神就掉坑里。关键记住:只要涉及“第几天”“几月几号”“今年第几周”,就必须跳出 Duration 思维,回到 time.Date 和 AddDate。


















