如何在go中获取几个月前的今天?你真的用对了吗?
如何在go中获取几个月前的今天?你真的用对了吗?
注意溢出
一般做法
func getMonthToday1(t time.Time)time.Time{
// today
fmt.Printf("today: [%s]\n", t)
// 获取1个月前的今天
return t.AddDate(0,-1,0)
}
打印结果:
today: [2022-09-07 23:37:20.096013 +0800 CST m=+0.000068580]
last month today: [2022-08-07 23:37:20.096013 +0800 CST]
看起来没啥问题,正常的很。一般思路肯定是首先想到这么写。
日期的溢出
// 将今天改为7月31号
today: [2022-07-31 00:00:00 +0800 CST]
last month today: [2022-07-01 00:00:00 +0800 CST]
按直觉性的思考,我这里是月末,上个月末不应该是6月31号吗?怎么是7月1号呢?这是因为日期溢出了,上月6月份只有30号,没有31号,所以加上溢出的一天就是7月1号。如果刚好目标月份是2月份,那么29号30号也有可能出现这么问题。这是我们在开发中要注意的,要写单元测试覆盖边界场景。
go中的日期加减
go的实现如下:
func (t Time) AddDate(years int, months int, days int) Time {
year, month, day := t.Date()
hour, min, sec := t.Clock()
return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec()), t.Location())
}
// Date中天数的计算:
// Add in days from 400-year cycles.
n := y / 400
y -= 400 * n
d := daysPer400Years * n
// Add in 100-year cycles.
n = y / 100
y -= 100 * n
d += daysPer100Years * n
// Add in 4-year cycles.
n = y / 4
y -= 4 * n
d += daysPer4Years * n
// Add in non-leap years.
n = y
d += 365 * n
// Add in days before this month.
d += uint64(daysBefore[month-1])
if isLeap(year) && month >= March {
d++ // February 29
}
// Add in days before today.
d += uint64(day - 1)
代码也很简单,大致逻辑就是从年算起,总共有多少年,闰年有多少,今天已经过完的月有多少,然后累加起来,算出一个从初始年到现在的天数,然后换算成秒,用秒计算,完事。
go这样的计算方式是很正规的,上个月末这个概念用AddDate其实是不合理的,go不会考虑你心目的月末。
正确计算月末
func getMonthToday2(t time.Time, month int)time.Time{
// today
fmt.Printf("today: [%s]\n", t)
// 判断天数范围 小于等于28天的计算,覆盖大多数情况
if t.Day()<=28{
return t.AddDate(0,-month,0)
}
// 月份的天数数组
monthDay := [13]int{0,31,28,31,30,31,30,31,31,30,31,30,31}
// 计算目标所在日期
target:=t.AddDate(0,0,1-t.Day()).AddDate(0,-month,0)
// 计算当月最大天数
targetDay:=monthDay[target.Month()]
// 计算闰年
if target.Month()==time.February&&(target.Year()%400==0||(target.Year()%100!=0&&target.Year()%4==0)){
targetDay++
}
if t.Day()>targetDay{
return target.AddDate(0,0,targetDay-1)
}
return target.AddDate(0,0,t.Day()-1)
}
// 打印如下:
today: [2022-07-31 00:00:00 +0800 CST]
last month today: [2022-06-30 00:00:00 +0800 CST]
这是我自己的写的代码,测试了一下是OK的。思路也比较简单。应该也有开源的库,但是我没找到。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下