
本文介绍在 Go 语言中准确获取当前月份首日与末日的标准方法,避免常见误区(如误用 time.Month 类型、错误推算月末日期),并提供可直接运行的健壮示例代码。
本文介绍在 go 语言中准确获取当前月份首日与末日的标准方法,避免常见误区(如误用 `time.month` 类型、错误推算月末日期),并提供可直接运行的健壮示例代码。
在 Go 中,time.Month 是一个枚举类型(type Month int),不能直接用于 time.Time.Add() 方法——该方法只接受 time.Duration 类型参数。因此,像 date.Add(time.Month) 这样的写法会导致编译错误。此外,即使强行通过时间偏移(如加30天再减1天)估算月末,也会因各月天数不均(28–31天)、闰年等因素导致结果不可靠,例如4月24日加一个月再减一天得到的是5月23日,而非4月30日。
✅ 正确做法是:先构造当月第一天,再基于它推算月末。Go 提供了 time.Date() 和 AddDate() 两个关键函数,能安全处理月份边界:
- time.Date(year, month, day, ...) 可精确创建指定年月日的 time.Time,自动适配时区;
- t.AddDate(0, 1, -1) 表示“在 t 的基础上增加 0 年、1 个月、再减 1 天”,即从当月1日跳转到下月1日,再回退1天 → 恰好是当月最后一天。
以下是完整、生产就绪的实现:
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
year, month, _ := now.Date() // 获取当前年份、月份(time.Month 类型)和日(忽略)
loc := now.Location() // 保留原始时区,避免默认 UTC 偏移
firstOfMonth := time.Date(year, month, 1, 0, 0, 0, 0, loc)
lastOfMonth := firstOfMonth.AddDate(0, 1, -1) // 安全跨月计算,自动处理2月/闰年等
fmt.Println("First day of month:", firstOfMonth.Format("2006-01-02"))
fmt.Println("Last day of month: ", lastOfMonth.Format("2006-01-02"))
}
? 关键注意事项:
- ✅ 始终使用 now.Location() 传递时区,否则 time.Date() 默认使用 time.UTC,可能导致本地时间偏差;
- ✅ AddDate() 是 Go 推荐的日期级运算方式(年/月/日),比基于 Duration 的 Add() 更可靠,因为它会智能处理月份天数变化(如1月31日 + 1月 = 2月28日或29日);
- ❌ 避免 Add(720 * time.Hour) 或 Add(30 * 24 * time.Hour) 等硬编码时长,它们无法应对不同月份长度;
- ? 如需复用,可封装为函数:
func FirstAndLastDayOfMonth(t time.Time) (first, last time.Time) {
y, m, _ := t.Date()
loc := t.Location()
first = time.Date(y, m, 1, 0, 0, 0, 0, loc)
last = first.AddDate(0, 1, -1)
return
}
此方法简洁、无依赖、零外部库,适用于所有 Go 版本(≥1.0),是获取当月起止日期的权威实践。











