问题描述:

I am relatively new to golang and mongodb and ran into a date issue where it appears that I can insert a UTC date into mongodb, but when I query through golang it is getting automatically converted to the local time. I want to get it back from mongodb in UTC with no conversion. Here is a quick example:

type SampleItem struct {

ObjId bson.ObjectId `bson:"_id,omitempty" json:"-"`

SampleDate time.Time `bson:"sampleDate" json:"sampleDate"`

}

func TestMe() {

var item SampleItem

var items []SampleItem

sess := getSession()

defer sess.Close()

item.SampleDate = time.Now().UTC()

fmt.Printf("%s\n", item.SampleDate)

collection := sess.DB("myCollection").C("sampleItems")

collection.Insert(item)

err := collection.Find(bson.M{}).All(&items)

if err == nil {

fmt.Printf("%s\n", items[0].SampleDate)

}

}

My output:

2014-10-12 04:10:50.3992076 +0000 UTC

2014-10-11 23:10:50.399 -0500 CDT

It appears that the mgo driver may be automatically converting it because when I query mongodb from a console window my date is in UTC. Am I missing a mgo option somewhere that turns this off?

网友答案:

Go time.Time values store an instant in time and a location. The mgo BSON decoder sets the location to time.Local.

You can set time.Local to the UTC location:

time.Local = time.UTC

A package designed to be used third parties should not modify the local location, but it's OK within the scope of an application.

The Time.UTC() method returns a time at the same instant in time as the receiver and the location set to UTC. This line will print the time in UTC:

    fmt.Printf("%s\n", items[0].SampleDate.UTC())

Because MongoDB stores time with lower precision than a time.Time, the value returned from MongoDB may not equal the value you stored.

网友答案:

I know I asked this question, but after lots of digging around I found this to be one possible option. By using a custom type from time.Time you can override the json serializer interfaces and force the use of UTC. However, is doing this type of thing recommended...

I have to give some credit to UNIX time stamps in Golang as well as the go source.

type JsonTime time.Time

func (t JsonTime) MarshalJSON() ([]byte, error) {
    tt := time.Time(t).UTC()
    if y := tt.Year(); y < 0 || y >= 10000 {
        return nil, errors.New("JsonTime: year outside of range [0,9999]")
    }
    if y := tt.Year(); y == 1 {
        return []byte{}, nil
    }
    return []byte(tt.Format(`"` + time.RFC3339Nano + `"`)), nil
}

func (t JsonTime) GetBSON() (interface{}, error) {
    if time.Time(t).IsZero() {
        return nil, nil
    }
    return time.Time(t), nil
}

func (t *JsonTime) SetBSON(raw bson.Raw) error {
    var tm time.Time

    if err := raw.Unmarshal(&tm); err != nil {
        return err
    }

    *t = JsonTime(tm)
    return nil
}

func (t JsonTime) String() string {
    return time.Time(t).UTC().String()
}

type SampleItem struct {
    ObjId      bson.ObjectId `bson:"_id,omitempty" json:"-"`
    SampleDate JsonTime      `bson:"sampleDate" json:"sampleDate"`
}

func TestMe() {

    var item SampleItem
    var items []SampleItem

    sess := getSession()
    defer sess.Close()

    item.SampleDate = JsonTime(time.Now().UTC())
    fmt.Printf("%s\n", item.SampleDate)

    collection := sess.DB("myCollection").C("sampleItems")
    collection.Insert(item)

    err := collection.Find(bson.M{}).All(&items)
    if err == nil {

        fmt.Printf("%s\n", items[0].SampleDate)
        if data, err := json.Marshal(items); err != nil {
            fmt.Printf("%v\n", err)
        } else {
            fmt.Printf("%s\n", data)
        }
    }
}
相关阅读:
Top