irvana
irvana

Reputation: 353

Go time comparison

I'm trying to create simple function just to change time zone of a time to another (Lets assume UTC to +0700 WIB). Here is the source code. I have 2 functions, first GenerateWIB which will change just your time zone into +0700 WIB with same datetime. Second is GenerateUTC which will change given time's timezone into UTC. GenerateUTC works perfectly while another is not.

expect := time.Date(2016, 12, 12, 1, 2, 3, 4, wib)
t1 := time.Date(2016, 12, 12, 1, 2, 3, 4, time.UTC)
res := GenerateWIB(t1)
if res != expect {
    fmt.Printf("WIB Expect %+v, but get %+v", expect, res)
}

The res != expect always fullfilled with this result.

WIB Expect 2016-12-12 01:02:03.000000004 +0700 WIB, but get 2016-12-12 01:02:03.000000004 +0700 WIB

But it is the same time right? Did i miss something?

Upvotes: 4

Views: 12985

Answers (2)

LeGEC
LeGEC

Reputation: 51870

There is an .Equal() method to compare dates :

if !res.Equal(expect) {
   ...

Quoting the doc :

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.

If you look at the code for the time.Time(*) struct, you can see that this struct has three private fields :

type Time struct {
    ...
    wall uint64
    ext  int64

    ...
    loc *Location
}

and the comments about those fields clearly indicate that, depending on how the Time struct was built, two Time describing the same point in time may have different values for these fields.

Running res == expect compares the values of these inner fields,
running res.Equal(expect) tries to do the thing you expect.


(*) time/time.go source code on master branch as of oct 27th, 2020

Upvotes: 7

sensorario
sensorario

Reputation: 21620

Dates in golang must be compared with Equal method. Method Date returns Time type.

func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time

and Time type have Equal method.

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.

Example

package main

import (
    "fmt"
    "time"
)

func main() {
    secondsEastOfUTC := int((8 * time.Hour).Seconds())
    beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)

    // Unlike the equal operator, Equal is aware that d1 and d2 are the
    // same instant but in different time zones.
    d1 := time.Date(2000, 2, 1, 12, 30, 0, 0, time.UTC)
    d2 := time.Date(2000, 2, 1, 20, 30, 0, 0, beijing)

    datesEqualUsingEqualOperator := d1 == d2
    datesEqualUsingFunction := d1.Equal(d2)

    fmt.Printf("datesEqualUsingEqualOperator = %v\n", datesEqualUsingEqualOperator)
    fmt.Printf("datesEqualUsingFunction = %v\n", datesEqualUsingFunction)

}

datesEqualUsingEqualOperator = false

datesEqualUsingFunction = true

resources

Upvotes: 1

Related Questions