2016-04-14 1 views
7

У меня есть time.Time, созданный с использованием time.Date(). Затем я рассчитываю количество наносекунд между 1970/1/1 00:00:00.000000000 и тем временем.Почему 2 временных структуры с одинаковой датой и временем возвращают false по сравнению с ==?

Затем я возьму наносекунды и верну их обратно в time.Time с помощью time.Unix().

Однако, если я сравниваю восстановленное время с оригиналом, используя ==, он возвращает false. Если я вычитаю эти 2 раза, результирующая продолжительность равна 0. Если я сравню эти 2 раза, используя time.Equal(), он вернет true.

Если я создаю другое время, используя time.Date() с теми же значениями, что и в первый раз, используя ==, чтобы сравнить это новое время, и исходное время приводит к истине.

Это код, который демонстрирует это (Golang Playground):

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    t1 := time.Date(2016, 4, 14, 1, 30, 30, 222000000, time.UTC) 


    base := time.Date(1970, 1, 1, 0, 0, 0, 0, t1.Location()) 
    nsFrom1970 :=t1.Sub(base).Nanoseconds() // Calculate the number of nanoseconds from 1970/1/1 to t1 

    t2 := time.Unix(0, nsFrom1970) 

    fmt.Println(t1) 
    fmt.Println(t2) 
    fmt.Println(t1.Sub(t2)) // 0 
    fmt.Println(t1 == t2) //false 
    fmt.Println(t1.Equal(t2)) //true 

    t3 := time.Date(2100, 2, 1, 21, 21, 21, 222000000, time.UTC) 
    fmt.Println(t1 == t3) //true 
} 

Почему восстановленное время возвращать ложь, когда по сравнению с исходным временем?

ответ

5

time.Time является struct. Когда вы пытаетесь сравнить их с ==, цитируя Spec: Comparison operator:

значения Struct сопоставимы, если все их поля сопоставимы. Два значения структуры равны, если их соответствующие поля не blank равны.

So t1 == t2 будет сравнивать все поля структурных значений 2 Time. Структура Time содержит не только вторую и наносекунду с базового времени, но также содержит местоположение в качестве указателя: *Location, поэтому == также сравнивает поля местоположения. Сравнение указателей:

Значения указателя сопоставимы. Два значения указателя равны, если они указывают на одну и ту же переменную или оба имеют значение nil. Указатели на разные zero-size переменные могут быть или не быть равными.

И поэтому сравнивая раз == дает false результат: 2 места может обозначать то же место, даже если их адрес отличается, и это ваш случай.

Чтобы доказать это:

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()) 

Выход:

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

Это отражено в time.Time:

Обратите внимание, что Go == оператор сравнивает не только время, но мгновенного также местоположение. Поэтому значения времени не должны использоваться в качестве ключей карты или базы данных без предварительного подтверждения того, что для всех значений установлено одинаковое местоположение, что может быть достигнуто с помощью метода UTC или Local.

Если t1 и t2 также будет содержать те же *Location указатель, они будут равны, даже если по сравнению с оператором ==. Это может быть обеспечено путем вызова метода Time.UTC() или Time.Local(), который возвращает значение time.Time, где используется указатель того же местоположения (*Location). Или с помощью метода Time.In(), который набор указанный указатель местоположения (после правильного преобразования) и т.д .:

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 

Выход:

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

Попробуйте на Go Playground.

Смежные вопросы