如何在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的。思路也比较简单。应该也有开源的库,但是我没找到。

posted @   松松哥、  阅读(121)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示