Go version
go1.20.8
Output of go env
in your module/workspace:
GO111MODULE="on"
GOARCH="arm64"
GOBIN=""
GOCACHE="/Library/Caches/go-build"
GOENV="/Library/Application Support/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="arm64"
GOHOSTOS="darwin"
GOINSECURE=""
GOMODCACHE="/go/pkg/mod"
GOOS="darwin"
GOPATH="/go"
GOPROXY="https://goproxy.cn,direct"
GOROOT="/go/go1.20.8"
GOSUMDB="off"
GOTMPDIR=""
GOTOOLDIR="/go/go1.20.8/pkg/tool/darwin_arm64"
GOVCS=""
GOVERSION="go1.20.8"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
What did you do?
There is a bug in the time library when adding or subtracting months. When the time is 15:00:00 on July 31, 2025 and 15:00:00 on August 31, 2025, the output is July and October when t. AddDate (0, -1,0) and t. AddDate (0, 1,0) are executed respectively
What did you see happen?
package main
import ( "fmt" "time" )
func main() { t, _ := time.ParseInLocation("2006-01-02 15:04:05", "2025-07-31 15:00:00", time.Local) fmt.Println(t.AddDate(0, -1, 0).String()) // 2025-07-01 15:00:00 +0800 t, _ = time.ParseInLocation("2006-01-02 15:04:05", "2025-08-31 15:00:00", time.Local) fmt.Println(t.AddDate(0, 1, 0).String()) // 2025-10-01 15:00:00 +0800 }
What did you expect to see?
2025-06-30 15:00:00 +0800 and 2025-09-30 15:00:00 +0800
Comment From: gabyhelp
Related Issues
- golang `time.AddDate` operation incorrect #65397 (closed)
- affected/package: time #63843 (closed)
- time AddDate() Calculate time last month #71069 (closed)
- time: Wrong `time.AddDate` calculation if months' last date is 31 #57139 (closed)
- time.AddDate() can't get Feb #31130 (closed)
- time: time ParseInLocation error #66987 (closed)
- time: time.ParseInLocation can get the seconds wrong #71444 (closed)
- time: AddDate with negative day changed behavior #68718 (closed)
- time: i find some problems when using addDate to do date calculation #66374 (closed)
- time: ParseInLocation error #49284 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: adonovan
The problem is that AddDate(+/- 1 month) simply increments/decrements the month column then normalizes, so:
- 31 Jul - 1 month = "31 Jun" = 1 Jul
- 31 Aug + 1 month = "31 Sep" = 1 Oct
Months are not of the same length, so there will always be an edge case trying to map from the last day to "the same day" of the next or previous month. This is a dup of several previous issues, as enumerated by gabyhelp (e.g. https://github.com/golang/go/issues/31145). We cannot change the behavior of AddDate at this point, even if we wanted to (though the previous issues suggest we do not). But this is a recurring source of surprise that should be better documented, and if there is one clear alternative algorithm that many users expect, we should provide it and refer to it.
Comment From: ALTree
It seems to be documented?
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.
Comment From: adonovan
It is documented, yet users are perennially confused enough to report issues. Perhaps it should provide more advice on how to safely work with month strides.
Comment From: ianlancetaylor
The existing documentation seems very clear to me. It explicitly says
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.
which is the exact case that the original poster is misunderstanding. Is there really anything we can do to make this more clear?
Comment From: seankhliao
I think this is more of a case where we provided an API which we shouldn't have, and users don't read the docs before trying to use something.