diff --git a/src/time/time.go b/src/time/time.go index edf0c6261026dd..2899c3849455dd 100644 --- a/src/time/time.go +++ b/src/time/time.go @@ -909,6 +909,37 @@ func (t Time) AddDate(years int, months int, days int) Time { return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec()), t.Location()) } +// AddDateX returns the time more attention to months then AddDate. +// For example, AddDateX(0, 1, 0) applied to 2021-08-31 +// will returns 2021-09-30. +// Because in most cases, the expectation is the change of months, +// so, process day after process year and month +// +// AddDateX if you want to normalizes the result like AddDate, +// You can set the optional param normalizes equal to true, +// It will be the same as the result of the function AddDate. +func (t Time) AddDateX(years int, months int, days int, normalizes ...bool) Time { + year, month, day := t.Date() + hour, min, sec := t.Clock() + + if len(normalizes) > 0 && normalizes[0] == true { + return Date(year+years, month+Month(months), day+days, hour, min, sec, int(t.nsec()), t.Location()) + } + + // Normalize month, overflowing into year. + m := int(month+Month(months)) - 1 + year, m = norm(year+years, m, 12) + month = Month(m) + 1 + + if lDay := daysIn(month, year); day > lDay { + // If the desired month does not have this day, + // temporarily set the day as the maximum day of the desired month, + // and then process the param days. + day = lDay + } + return Date(year, month, day+days, hour, min, sec, int(t.nsec()), t.Location()) +} + const ( secondsPerMinute = 60 secondsPerHour = 60 * secondsPerMinute diff --git a/src/time/time_test.go b/src/time/time_test.go index e2fb897b6d6edc..e254a2acb843e1 100644 --- a/src/time/time_test.go +++ b/src/time/time_test.go @@ -674,6 +674,27 @@ func TestAddDate(t *testing.T) { } } +var addDateXTests = []struct { + years, months, days int +}{ + {4, 6, 0}, + {3, 18, 0}, + {5, -6, 0}, +} + +func TestAddDateX(t *testing.T) { + t0 := Date(2021, 10, 31, 16, 8, 8, 0, UTC) + t1 := Date(2026, 4, 30, 16, 8, 8, 0, UTC) + for _, at := range addDateXTests { + time := t0.AddDateX(at.years, at.months, at.days) + if !time.Equal(t1) { + t.Errorf("AddDateX(%d, %d, %d) = %v, want %v", + at.years, at.months, at.days, + time, t1) + } + } +} + var daysInTests = []struct { year, month, di int }{