Why do 2 time structs with the same date and time return false when compared with ==?

time.Time is a struct. When you try to compare them with ==, quoting from the Spec: Comparison operator:

Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.

So t1 == t2 will compare all the fields of the 2 Time struct values. The Time struct contains not just the second and nanosecond since a base time, it also contains the location as a pointer: *Location, so == will also compare the location fields. Comparing pointers:

Pointer values are comparable. Two pointer values are equal if they point to the same variable or if both have value nil. Pointers to distinct zero-size variables may or may not be equal.

And this is why comparing the times with == gives a false result: 2 locations may denote the same location even if their address is different, and this is your case.

To prove this:

fmt.Println("Locations:", t1.Location(), t2.Location())
fmt.Printf("Location pointers: %p %p\n", t1.Location(), t2.Location())
fmt.Println("Locations equal:", t1.Location() == t2.Location())

Output:

Locations: UTC UTC
Location pointers: 0x1e2100 0x1e6de0
Locations equal: false

This is documented in time.Time:

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.

If t1 and t2 would also contain the same *Location pointer, they would be equal even if compared with the == operator. This can be ensured by calling Time.UTC() or Time.Local() method on them which returns a time.Time value where the same location pointer (*Location) is used. Or by using the Time.In() method which will set the specified location pointer (after the proper conversion), e.g.:

t2 = t2.In(t1.Location())
fmt.Println("Locations:", t1.Location(), t2.Location())
fmt.Printf("Location pointers: %p %p\n", t1.Location(), t2.Location())
fmt.Println("Locations equal:", t1.Location() == t2.Location())
fmt.Println(t1 == t2)     // Now true
fmt.Println(t1.Equal(t2)) // Still true

Output:

Locations: UTC UTC
Location pointers: 0x1e2100 0x1e2100
Locations equal: true
true
true

Try it on the Go Playground.

Leave a Comment