-
Notifications
You must be signed in to change notification settings - Fork 18.4k
Description
Please answer these questions before submitting your issue. Thanks!
What version of Go are you using (go version
)?
go version go1.9rc2 darwin/amd64
this does not happen, for contrast, with go1.8.3 darwin/amd64
This change is documented at the top of the new go1.9rc2 time/time.go file:
// For debugging, the result of t.String does include the monotonic
// clock reading if present. If t != u because of different monotonic clock readings,
// that difference will be visible when printing t.String() and u.String().
This is actually a rather drastic proposed change. I refer not the use of the monotone clock, but the display of it in timestamps formated via String(). Many of us use String() for many purposes other than debugging. For debugging, a separate new StringWithMonotone() should be provided.
What operating system and processor architecture are you using (go env
)?
go env:
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/jaten/go"
GORACE=""
GOROOT="/usr/local/go1.9rc2"
GOTOOLDIR="/usr/local/go1.9rc2/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/6s/zdc0hvvx7kqcglg5yqm3kl4r0000gn/T/go-build055854381=/tmp/go-build -gno-record-gcc-switches -fno-common"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
What did you do?
Here code to reproduce the issue, serialize_time.go
. It is extracted from the time.Time serialization in a popular msgpack serialization package. e.g. getunix() and putunix() are here https://github.com/tinylib/msgp/blob/ad0ff2e232ad2e37faf67087fb24bf8d04a8ce20/msgp/integers.go#L113
package main
import (
"fmt"
"time"
)
func main() {
// time to bytes
t := time.Now()
fmt.Printf("original t='%s'\n", t.String())
t = t.UTC()
fmt.Printf("original t='%s' in UTC\n", t.String())
var b [12]byte
putUnix(b[:], t.Unix(), int32(t.Nanosecond()))
// bytes to time:
sec, nsec := getUnix(b[:])
t2 := time.Unix(sec, int64(nsec)).Local()
fmt.Printf("restored t2='%s'\n", t2.String())
}
/* output of main:
original t='2017-08-16 19:35:41.958759249 -0400 EDT m=+0.000241395'
original t='2017-08-16 23:35:41.958759249 +0000 UTC' in UTC
restored t2='2017-08-16 19:35:41.958759249 -0400 EDT'
*/
func getUnix(b []byte) (sec int64, nsec int32) {
sec = (int64(b[0]) << 56) | (int64(b[1]) << 48) |
(int64(b[2]) << 40) | (int64(b[3]) << 32) |
(int64(b[4]) << 24) | (int64(b[5]) << 16) |
(int64(b[6]) << 8) | (int64(b[7]))
nsec = (int32(b[8]) << 24) | (int32(b[9]) << 16) | (int32(b[10]) << 8) | (int32(b[11]))
return
}
func putUnix(b []byte, sec int64, nsec int32) {
b[0] = byte(sec >> 56)
b[1] = byte(sec >> 48)
b[2] = byte(sec >> 40)
b[3] = byte(sec >> 32)
b[4] = byte(sec >> 24)
b[5] = byte(sec >> 16)
b[6] = byte(sec >> 8)
b[7] = byte(sec)
b[8] = byte(nsec >> 24)
b[9] = byte(nsec >> 16)
b[10] = byte(nsec >> 8)
b[11] = byte(nsec)
}
In summary, in go1.9rc2, time.Time.String() may produce:
2017-08-16 18:41:39.184829495 -0400 EDT m=+0.057013769
whereas in go1.83, the String() applied to the same value produces always:
2017-08-16 18:41:39.184829495 -0400 EDT
While not a language consistency issue, this is a backwards-compatibility issue for programs that expected one thing from their time.Time values. For example, my tests in a fork of the tinylib/msgp lib cited above are suddenly broken under go1.9rc2. So these changes may break many programs unexpectedly when moving from go1.8.3 to go1.9.
I'm glad for the new monotonic time feature under the covers, as it solves bugs with walltime going through leap seconds, but does it have to surface itself into the string representation of time in a non-backcompatible way? For the new info, how about adding a separate stringification method if one needs both timestamps? Perhaps: StringWithMonotone() alongside the old fashioned String().
In summary, while useful, features meant for debugging the new time.Time values should not break backwards compatibility, when they can trivially be provided alongside in a separate new method.