简体   繁体   English

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

[英]time.Duration is unexpectedly 'divided' by 1'000'000

I'm using time.Duration to store data in a struct as follows: 我正在使用time.Duration将数据存储在结构中,如下所示:

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. 然后我使用mgo将数据插入数据库。

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) ). 在创建data实例之后,插入数据之前,我做了检查,并且ExpiredIn的值为ExpiredIn ,但是在MongoDB中,它变为604'800'000(或NumberLong(604800000) )。

Any idea why? 知道为什么吗? Thank you! 谢谢!

We would normally write custom MarshalJSON/UnmarshalJSON for specific types to control what happens to their values before/after marshaling/unmarshaling. 我们通常会为特定类型编写自定义的MarshalJSON / UnmarshalJSON,以控制在编组/解组之前/之后它们的值发生什么。

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! 大功告成!

在此处输入图片说明

Current solution: multiply the returned ExpiredIn from MongoDB with time.Second so I got my Go-flavoured nanosecond time.Duration . 目前的解决方案:乘返回 ExpiredIn从MongoDB中与 time.Second所以我得到了我去味纳秒 time.Duration

I ended up using the string representation of time.Duration because it simply works. 我最终使用time.Durationstring表示形式,因为它很简单。

I created two functions for my ApiAccessToken struct that does the job of writing/reading the data. 我为ApiAccessToken结构创建了两个函数, ApiAccessToken函数完成了写入/读取数据的工作。

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! 瞧,它起作用了!

串

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM