2016-04-14 20 views
7

Mam time.Time utworzony przy użyciu time.Date(). Następnie obliczyłem liczbę nanosekund między 1970/1/1 00:00:00.000000000 i tym razem.Dlaczego 2-składnikowe konstrukcje z tą samą datą i czasem zwracają fałsz w porównaniu z ==?

Następnie biorę nanosekundy i zamieniam je z powrotem w time.Time używając time.Unix().

Jednak jeśli porówna się czas odtworzony z oryginałem przy użyciu ==, zwraca wartość false. Jeśli odejmuję je 2 razy, wynikowy czas wynosi 0. Jeśli porówna się te 2 razy, używając time.Equal(), zwraca wartość true.

Jeśli utworzę inny czas przy użyciu time.Date() z tymi samymi wartościami, co za pierwszym razem, użycie == w celu porównania tego nowego czasu z oryginalnym czasem daje w wyniku wartość true.

Jest to kod, który demonstruje ten (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 
} 

Dlaczego czas odtworzony return false w porównaniu z czasem pierwotnego?

Odpowiedz

5

time.Time to struct. Podczas próby porównać je z ==, cytując z Spec: Comparison operator:

wartości struktury są porównywalne, jeżeli wszystkie ich pola są porównywalne. Dwie wartości struct są równe, jeśli odpowiadające im pola inne niż blank są równe.

Tak więc t1 == t2 będzie porównywać wszystkie pola z wartościami strukturalnymi 2 Time. Struktura Time zawiera nie tylko sekundę i nanosekundę od czasu podstawowego, ale zawiera także lokalizację jako wskaźnik: *Location, więc == będzie również porównywać pola lokalizacji. Porównanie wskaźników:

Wartości wskaźników są porównywalne. Dwie wartości wskaźnika są równe, jeśli wskazują na tę samą zmienną lub oba mają wartość nil. Wskaźniki do różnych zmiennych zero-size mogą być lub nie być równe.

I dlatego porównanie czasów z == daje false wynik: 2 lokalizacje może oznaczać tę samą lokalizację, nawet jeśli ich adres jest inny, a to jest twoja sprawa.

Aby to udowodnić:

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

wyjściowa:

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

Jest to udokumentowane w time.Time:

Zauważ, że Go == operator nie porównuje tylko czas ale błyskawicznych także Lokalizacja. Dlatego wartości czasu nie powinny być używane jako klucze mapy lub bazy danych bez uprzedniego zagwarantowania, że ​​identyczna lokalizacja została ustawiona dla wszystkich wartości, co można osiągnąć za pomocą metody UTC lub lokalnej.

Jeśli t1 i t2 również zawierają ten sam wskaźnik *Location, byłyby równe, nawet w porównaniu z operatorem ==. Można to zapewnić, wywołując metodę Time.UTC() lub Time.Local(), która zwraca wartość time.Time, w której używany jest ten sam wskaźnik lokalizacji (*Location). Lub za pomocą metody Time.In() które ustawiony określony wskaźnik lokalizacji (po odpowiedniej konwersji), np .:

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 

wyjściowa:

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

Spróbuj na Go Playground.