时间意外地将时间除以1'000'000

I'm using time.Duration to store data in a struct as follows:

type ApiAccessToken struct {
    ...
    ExpiredIn   *time.Duration `bson:"expired_in,omitempty" json:"expired_in,omitempty"`
    ...
}

and I set it using a constant like this:

...
const ApiAccessTokenDefaultExpiresIn = 7 * 24 * time.Hour
...
d := ApiAccessTokenDefaultExpiresIn
data := &ApiAccessToken{
    ...
    ExpiredIn: &d
    ...
}
...

then I use mgo to insert the data to database.

I did checking after creating the data instance and before inserting the data and the value of ExpiredIn was 604'800'000'000'000 but in MongoDB it became 604'800'000 (or NumberLong(604800000)).

Any idea why? Thank you!

Current solution: multiply the returned ExpiredIn from MongoDB with time.Second so I got my Go-flavoured nanosecond time.Duration.

I ended up using the string representation of time.Duration because it simply works.

I created two functions for my ApiAccessToken struct that does the job of writing/reading the data.

func (tok *ApiAccessToken) SetExpiredIn(t time.Duration) {
    s := t.String() // read the string
    tok.ExpiredIn = &s
}

func (tok *ApiAccessToken) GetExpiredIn() (r bool, t time.Duration) {
    if tok.ExpiredIn != nil {
        var err error
        t, err = time.ParseDuration(*tok.ExpiredIn) // parse the string
        r = (err == nil)                            // can we use this?
    }
    return
}

And voila, it works!

string

We would normally write custom MarshalJSON/UnmarshalJSON for specific types to control what happens to their values before/after marshaling/unmarshaling.

type ExpiredIn struct {
    time.Duration
}

func (e *ExpiredIn) MarshalJSON() ([]byte, error) {
    return []byte(string(e.Nanoseconds())), nil
}

func (e *ExpiredIn) UnmarshalJSON(data []byte) error {
    i, _ := strconv.ParseInt(string(data[:])), 10, 64)
    e.Duration = time.Duration(i)
    return nil

}

Here's the test code:

package main

import (
    "log"
    "time"

    "gopkg.in/mgo.v2"
)

type Token struct {
    ExpiredIn time.Duration
}

type ExpiredIn struct {
    time.Duration
}

func (e *ExpiredIn) MarshalJSON() ([]byte, error) {
    return []byte(string(e.Nanoseconds())), nil
}

func main() {
    session, err := mgo.Dial("mongodb://localhost:27017/test")
    if err != nil {
        panic(err)
    }
    defer session.Close()

    // Optional. Switch the session to a monotonic behavior.
    session.SetMode(mgo.Monotonic, true)

    c := session.DB("test").C("tokens")
    err = c.Insert(&Recipe{7 * 24 * time.Hour})
    if err != nil {
        log.Fatal(err)
    }
}

And you're done!

enter image description here