Marshal and Unmarshal a time.Time, Got different v

2020-07-25 10:28发布

I am try to update my Go code from 1.8 to 1.9. but, i got some problem:

package simple_struct

import (
    "time"
    "encoding/json"
    "github.com/stretchr/testify/assert"
    "testing"
)

type SimpleStruct struct {
    CreateTime time.Time
    Other      string
}

func NewSimpleStruct() *SimpleStruct {
    return &SimpleStruct{
        CreateTime: time.Now(),
    }
}

func Test(t *testing.T) {
    s1 := NewSimpleStruct()
    data, err := json.Marshal(s1)
    assert.Nil(t, err)
    s2 := &SimpleStruct{}
    err = json.Unmarshal(data, s2)
    assert.Nil(t, err)

    assert.Equal(t, s2, s1)
    // this is not equal
    // output:
    /*

    Diff:
    --- Expected
    +++ Actual
    @@ -1,3 +1,3 @@
    (*simple_struct.SimpleStruct)({
        - CreateTime: (time.Time) 2017-12-01 14:54:53.948875421 +0800 CST,
        + CreateTime: (time.Time) 2017-12-01 14:54:53.948875421 +0800 CST m=+0.001827244,
    */
}

It is working in Golang 1.8, but not in Golang 1.9.

I know that Golang 1.9 has update time.Time, but I do not understand this.

标签: json go
2条回答
smile是对你的礼貌
2楼-- · 2020-07-25 10:54

Package time

import "time"

Note that the Go == operator compares not just the time instant but also the Location and the monotonic clock reading.

func (Time) Equal

func (t Time) Equal(u Time) bool

Equal reports whether t and u represent the same time instant. Two times can be equal even if they are in different locations. For example, 6:00 +0200 CEST and 4:00 UTC are Equal. See the documentation on the Time type for the pitfalls of using == with Time values; most code should use Equal instead.


// A Time represents an instant in time with nanosecond precision.
//
// Time instants can be compared using the Before, After, and Equal methods.
//
// Note that the Go == operator compares not just the time instant but also the
// Location and the monotonic clock reading. Therefore, Time values should not
// be used as map or database keys without first guaranteeing that the
// identical Location has been set for all values, which can be achieved
// through use of the UTC or Local method, and that the monotonic clock reading
// has been stripped by setting t = t.Round(0). In general, prefer t.Equal(u)
// to t == u, since t.Equal uses the most accurate comparison available and
// correctly handles the case when only one of its arguments has a monotonic
// clock reading.
//
type Time struct {
// wall and ext encode the wall time seconds, wall time nanoseconds,
// and optional monotonic clock reading in nanoseconds.
//
// From high to low bit position, wall encodes a 1-bit flag (hasMonotonic),
// a 33-bit seconds field, and a 30-bit wall time nanoseconds field.
// The nanoseconds field is in the range [0, 999999999].
// If the hasMonotonic bit is 0, then the 33-bit field must be zero
// and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext.
// If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit
// unsigned wall seconds since Jan 1 year 1885, and ext holds a
// signed 64-bit monotonic clock reading, nanoseconds since process start.
wall uint64
ext  int64

// loc specifies the Location that should be used to
// determine the minute, hour, month, day, and year
// that correspond to this Time.
// The nil location means UTC.
// All UTC times are represented with loc==nil, never loc==&utcLoc.
loc *Location
}

It has long been the case, not just now (go1.9 +), that it is wrong to compare Go time.Times by comparing the implementation (opaque struct) with the Go equal operator (==). For example, as far back as go1.4,

Note that the Go == operator compares not just the time instant but also the Location. Therefore, Time values should not be used as map or database keys without first guaranteeing that the identical Location has been set for all values, which can be achieved through use of the UTC or Local method.

go1.9 merely added an additional element, a monotonic value, to the opaque time.Time struct.


Always use the time.Equal method to assert time.Time equality.

For example,

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now() // wall, location, & monotonic
    fmt.Println("Now:   ", now)
    clock := now.Round(0) // wall & location
    fmt.Println("Clock: ", clock)
    utc := now.UTC() // wall & location UTC
    fmt.Println("UTC:   ", utc)
    fmt.Println("now.Equal(clock)", now.Equal(clock)) // true
    fmt.Println("now == clock    ", now == clock)     // false
    fmt.Println("now.Equal(utc)  ", now.Equal(utc))   // true
    fmt.Println("now == utc      ", now == utc)       // false
    fmt.Println("clock.Equal(utc)", clock.Equal(utc)) // true
    fmt.Println("clock == utc    ", clock == utc)     // false
}

Playground: https://play.golang.org/p/VbFV2AcYw-

Output:

Now:    2017-12-01 14:54:15.168706745 -0500 EST m=+0.000899521
Clock:  2017-12-01 14:54:15.168706745 -0500 EST
UTC:    2017-12-01 19:54:15.168706745 +0000 UTC
now.Equal(clock) true
now == clock     false
now.Equal(utc)   true
now == utc       false
clock.Equal(utc) true
clock == utc     false
查看更多
相关推荐>>
3楼-- · 2020-07-25 11:00

Probably to do with monotonic time being wiped by marshalling. See the the package docs

查看更多
登录 后发表回答