duanpao4522 2018-08-28 15:58
浏览 82
已采纳

在Go中的mongodb驱动程序中进行比较以及可能以其他语言和其他数据库进行比较时的时间精度问题

I was learning Go and Mongodb, currently using the alpha official mongodb driver. Although it is in alpha, it is quite functional for basic usage I think. But I got an interesting issue on time conversion in this db driver.

Basically, I created a custom typed struct object, and marshaled it to bson document, and then convert the bson document back to struct object.

//check github.com/mongodb/mongo-go-driver/blob/master/bson/marshal_test.go
func TestUserStructToBsonAndBackwards(t *testing.T) {
u := user{
    Username:          "test_bson_username",
    Password:          "1234",
    UserAccessibility: "normal",
    RegisterationTime: time.Now(), //.Format(time.RFC3339), adding format result a string
}

//Struct To Bson
bsonByteArray, err := bson.Marshal(u)
if err != nil {
    t.Error(err)
}
//.UnmarshalDocument is the same as ReadDocument
bDoc, err := bson.UnmarshalDocument(bsonByteArray)
if err != nil {
    t.Error(err)
}
unameFromBson, err := bDoc.LookupErr("username")
//so here the binding is working for bson object too, the bind field named username ratherthan Username
if err != nil {
    t.Error(err)
}
if unameFromBson.StringValue() != "test_bson_username" {
    t.Error("bson from user struct Error")
}

//Bson Doc to User struct
bsonByteArrayFromDoc, err := bDoc.MarshalBSON()
if err != nil {
    t.Error(err)
}

var newU user
err = bson.Unmarshal(bsonByteArrayFromDoc, &newU)
if err != nil {
    t.Error(err)
}

if newU.Username != u.Username {
    t.Error("bson Doc to user struct Error")
}

//here we have an issue about time format.
if newU != u {
    log.Println(newU)
    log.Println(u)
    t.Error("bson Doc to user struct time Error")
}
}

However since my struct object has a time field, the result struct object contains a less accurate time value than the original. Then the comparison is failed.

=== RUN   TestUserStructToBsonAndBackwards
{test_bson_username 1234     0001-01-01 00:00:00 +0000 UTC   2018-08-28 23:56:50.006 +0800 CST 0001-01-01 00:00:00 +0000 UTC normal }
{test_bson_username 1234     0001-01-01 00:00:00 +0000 UTC   2018-08-28 23:56:50.006395949 +0800 CST m=+0.111119920 0001-01-01 00:00:00 +0000 UTC normal }
--- FAIL: TestUserStructToBsonAndBackwards (0.00s)
    model.user_test.go:67: bson Doc to user struct time Error

So I would like to ask many questions from this.

  1. How to compare time properly in this case ?

  2. What's the best way to store time in database to avoid such precision issue ? I think the time in database should not be a string.

  3. is this a db driver bug ?

  • 写回答

2条回答 默认 最新

  • doushi1960 2018-08-28 16:07
    关注

    Times in BSON are represented as UTC milliseconds since the Unix epoch (spec). Time values in Go have nanosecond precision.

    To round trip time.Time values through BSON marshalling, use times truncated to milliseconds since the Unix epoch:

    func truncate(t time.Time) time.Time {
        return time.Unix(0, t.UnixNano()/1e6*1e6)
    }
    
    ...
    
    u := user{
        Username:          "test_bson_username",
        Password:          "1234",
        UserAccessibility: "normal",
        RegisterationTime: truncate(time.Now()), 
    }
    

    You can also use the Time.Truncate method:

    u := user{
        Username:          "test_bson_username",
        Password:          "1234",
        UserAccessibility: "normal",
        RegisterationTime:  time.Now().Truncate(time.Milliseconds),
    }
    

    This approach relies on the fact that Unix epoch and Go zero time differ by a whole number of milliseconds.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog