Golang / mgo:如何在mongodb中按GMT + 8时区存储ISODate?

If I store ISODate in mongodb,the ISODate is always GMT+0

type StoreTime struct {
    storeTime time.Time `bson:"testTime" json:"testTime,omitempty"`
}
...
t := StoreTime {
    storeTime : time.Now(),
}
....
c.Insert(t)

The result is :

{ 
    "_id" : ObjectId("578b43e5feaa0deb6a94b1d0"),  
    "storeTime" : ISODate("2016-07-17T08:38:25.316+0000")
}

How can I change the time zone?

time.Now should return local time. Is your system time setup properly? What do you get on running the date command (on linux based system)?

You can try using In method on you time object with a time.Location value:

l, _ := time.LoadLocation("Local") // or the name of your time zone
t : time.Now()

t := StoreTime {
    storeTime : t.In(l),
}

You came across an intricacy of mgo.v2/bson, which converts Since the BSON specification states that all times shall be stored as

UTC milliseconds since the Unix epoch

mgo.v2/bson converts all time.Time values to UTC. So even when you explicitly set the location info of a time returned by time.Now() or companions, this local time is converted to UTC.

So in order to display time correctly for any given time zone, you should do the following:

  1. When saving a time.Time value, you should use the time as returned by time.Time.In(*time.Location) if the time zone differs from your (the servers) local time.
  2. When displaying the returned value in UTC, make sure you use time.Time.UTC()
  3. When displaying the returned value in a given local time, make sure you use time.Time.In(*time.Location) again.

To be a more clear on that, please have a look at the example below:

package main

import (
    "fmt"
    "time"

    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

const (
    myLoc = "Europe/Berlin"
    ny    = "America/New_York"
)

// We define those vars here, as you might want to make them
// package-global
var (
    berlin *time.Location
    nyc    *time.Location
)

// StoreTime is just a dummy struct
type StoreTime struct {
    // Unexported fields are not (un-)marshalled by encoding/json
    // and mgo.v2/bson, so the field name has to be uppercase
    StoreTime time.Time `bson:"testTime"`
}

func main() {

    var (
        sess *mgo.Session
        err  error
    )

    // Connect to MongoDB
    if sess, err = mgo.Dial("localhost:27017"); err != nil {
        panic("Could not connect to MongoDB: " + err.Error())
    }
    // Make sure the session is closed when main exits for whatever reason
    defer sess.Close()

    // Clear the collection for demo purposes
    if err = sess.DB("test").C("timezones").Remove(bson.M{}); err != nil && err != mgo.ErrNotFound {
        panic("Could not clean test collection: " + err.Error())
    }

    // Load the desired TZ by location
    if berlin, err = time.LoadLocation(myLoc); err != nil {
        panic("Error loading '" + myLoc + "' as timezone location: " + err.Error())
    }

    // Create a new StoreTime with the local time of the desired timezone.
    // Note that mgo.v2/bson still converts it to Zulu time, but with the
    // appropriate offset.
    st := &StoreTime{StoreTime: time.Now().In(berlin)}

    // Save the document for further reference
    if err = sess.DB("test").C("timezones").Insert(st); err != nil {
        panic("Error inserting sample document into MongoDB: " + err.Error())
    }

    // Load the saved document,...
    res := &StoreTime{}
    if err = sess.DB("test").C("timezones").Find(nil).One(&res); err != nil {
        panic("Unable to load just recently stored document: " + err.Error())
    }

    // ... and another TZ for displaying,...
    if nyc, err = time.LoadLocation(ny); err != nil {
        panic("Error loading '" + ny + "' as timezone location: " + err.Error())
    }

    // ...and display the time from the document in UTC and the local time
    // of both Berlin and NYC.
    fmt.Println(res.StoreTime.UTC())
    // The next two are identical for _me_, as I happen to live in the according TZ.
    // Unless you do, too, you should have different values
    fmt.Println(res.StoreTime.In(Berlin))
    fmt.Println(res.StoreTime)
    fmt.Println(res.StoreTime.In(nyc))
}