t = Time.parse("2020-03-31 12:00:00")
t + 1.month # => 2020-04-30 12:00:00 +0800
# 或者
1.month.after(t) # => 2020-04-30 12:00:00 +0800
loc, _ := time.LoadLocation("Asia/Shanghai")
t := time.Date(2010, 3, 31, 12, 0, 0, 0, loc) # => 2020-03-31 12:00:00 +0800
newTime := t.AddDate(0, 1, 0) # => 2020-05-01 12:00:00 +0800
fmt.Println(newTime)
# 输出 2020-05-01 12:00:00 +0800
最后得出的时间是 2020-05-01 12:00:00 +0800
, 和预期的不太一样,
是因为4月没有31号,所以会变成5月1号。
// AddDate returns the time corresponding to adding the
// given number of years, months, and days to t.
// For example, AddDate(-1, 2, 3) applied to January 1, 2011
// returns March 4, 2010.
//
// AddDate normalizes its result in the same way that Date does,
// so, for example, adding one month to October 31 yields
// December 1, the normalized form for November 31.
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())
}
注释中已经说明了此问题,只是我们使用时,并没有认真去考究,而是想当然的认为。
为了达到和ruby中类似的效果,我自己实现了一个,只能增减 年,月, 如果要天,还是一样会出现问题, 所以不考虑天的增减:
import (
"github.com/jinzhu/now"
"time"
)
// AddDate 时间增减
// 类似于ruby中的时间增减,和 time.AddDate 不同
// 如:
// loc, _ := time.LoadLocation("Asia/Shanghai")
// t := time.Date(2010, 3, 31, 12, 0, 0, 0, loc)
// utils.AddDate(t, 0, 1)
// => 2010-04-30 12:00:00 +0800 CST
// 不会因为4月没有31号,而变成5月1号
func AddDate(t time.Time, years int, months int) time.Time {
year, month, day := t.Date()
hour, min, sec := t.Clock()
// firstDayOfMonthAfterAddDate: years 年,months 月后的 那个月份的1号
firstDayOfMonthAfterAddDate := time.Date(year+years, month+time.Month(months), 1,
hour, min, sec, t.Nanosecond(), t.Location())
// firstDayOfMonthAfterAddDate 月份的最后一天
lastDay := now.New(firstDayOfMonthAfterAddDate).EndOfMonth().Day()
// 如果 t 的天 > lastDay,则设置为lastDay
// 如:t 为 2020-03-31 12:00:00 +0800,增加1个月,为4月31号
// 但是4月没有31号,则设置为4月最后一天lastDay(30号)
if day > lastDay {
day = lastDay
}
return time.Date(year+years, month+time.Month(months), day,
hour, min, sec, t.Nanosecond(), t.Location())
}