You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用MongoDB Go驱动将BSON Double转换为time.Time类型?

解决MongoDB Go驱动解码Double毫秒时间戳到time.Time的问题

MongoDB Go驱动v1.16.0没有内置配置直接处理这种混合类型的日期字段,但可以通过自定义BSON解码器实现兼容,同时支持标准BSON日期和Double类型的毫秒时间戳解码到time.Time字段。

实现步骤

  • 编写自定义解码函数,判断字段的BSON类型:
    • 若为BSON日期类型,直接解码为time.Time
    • 若为BSON Double类型,先转换为int64毫秒数,再转为time.Time
  • 将解码器注册到驱动的bsoncodec.Registry中
  • 连接数据库时使用该自定义Registry

完整代码示例

package main

import (
	"context"
	"fmt"
	"time"

	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/bsoncodec"
	"go.mongodb.org/mongo-driver/bson/bsonrw"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type Dummy struct {
	Id          int        `bson:"_id"`
	CreatedDate *time.Time `bson:"createdDate"`
}

// 自定义time.Time解码器,兼容BSON日期和Double毫秒时间戳
func customTimeDecoder(_ bsoncodec.DecodeContext, vr bsonrw.ValueReader, val bsoncodec.Value) error {
	switch vr.Type() {
	case bson.TypeDateTime:
		// 处理标准BSON日期
		dt, err := vr.ReadDateTime()
		if err != nil {
			return err
		}
		t := time.UnixMilli(dt)
		*val.Interface().(*time.Time) = t
		return nil
	case bson.TypeDouble:
		// 处理Double类型的毫秒时间戳
		ms, err := vr.ReadDouble()
		if err != nil {
			return err
		}
		t := time.UnixMilli(int64(ms))
		*val.Interface().(*time.Time) = t
		return nil
	default:
		return fmt.Errorf("cannot decode %v into time.Time", vr.Type())
	}
}

func main() {
	// 创建自定义Registry
	registry := bson.NewRegistry()
	// 注册自定义time.Time解码器
	registry.RegisterTypeDecoder(
		bson.TypeDateTime,
		bsoncodec.ValueDecoderFunc(customTimeDecoder),
	)
	// 注册Double类型到time.Time的解码逻辑
	registry.RegisterTypeDecoder(
		bson.TypeDouble,
		bsoncodec.ValueDecoderFunc(customTimeDecoder),
	)

	// 连接数据库时指定自定义Registry
	clientOpts := options.Client().ApplyURI("mongodb://localhost:27017").SetRegistry(registry)
	client, err := mongo.Connect(context.TODO(), clientOpts)
	if err != nil {
		panic(err)
	}
	defer client.Disconnect(context.TODO())

	// 测试查询
	coll := client.Database("test").Collection("dummy")
	var result Dummy
	err = coll.FindOne(context.TODO(), bson.M{"_id": 1}).Decode(&result)
	if err != nil {
		panic(err)
	}
	fmt.Printf("ID: %d, CreatedDate: %v\n", result.Id, result.CreatedDate)
}

关键说明

  • 自定义解码器会先识别字段的BSON类型,分别处理两种格式的日期数据
  • 必须同时注册bson.TypeDateTime和bson.TypeDouble到time.Time的解码逻辑,才能覆盖两种场景
  • 连接客户端时通过SetRegistry传入自定义Registry,驱动就会使用我们的解码规则处理数据

这样就能同时兼容两种格式的createdDate字段,解决解码报错问题。

内容的提问来源于stack exchange,提问作者takanuva15

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 19:53:12