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

如何用Golang将指定格式字符串转为ISODate插入MongoDB?

解决自定义日期格式转MongoDB ISODate的问题

问题原因

Gin的ShouldBindJSON默认仅支持RFC3339等标准JSON日期格式,无法直接解析Mon Jan 30 2023 17:27:16 GMT+0200 (Eastern European Standard Time)这类非标准格式到primitive.DateTime,因此会返回Bad Request错误。

解决方案

方法一:自定义字段实现UnmarshalJSON接口

修改Transaction结构体的JSON解析逻辑,让它能识别目标日期格式:

import (
    "encoding/json"
    "time"
    "go.mongodb.org/mongo-driver/bson/primitive"
)

type Transaction struct {
    ID       primitive.ObjectID `json:"id" bson:"_id"`
    Category primitive.ObjectID `bson:"category,omitempty"`
    Amount   string             `json:"amount" binding:"required"`
    Owner    primitive.ObjectID `bson:"owner,omitempty"`
    Date     primitive.DateTime `bson:"date" json:"date"`
}

// 自定义JSON反序列化方法,处理特殊日期格式
func (t *Transaction) UnmarshalJSON(data []byte) error {
    // 定义临时结构体,用string接收Date字段
    type TempTx struct {
        ID       primitive.ObjectID `json:"id"`
        Category primitive.ObjectID `json:"category,omitempty"`
        Amount   string             `json:"amount"`
        Owner    primitive.ObjectID `json:"owner,omitempty"`
        Date     string             `json:"date"`
    }

    var temp TempTx
    if err := json.Unmarshal(data, &temp); err != nil {
        return err
    }

    // 按目标格式解析日期到time.Time
    layout := "Mon Jan 02 2006 15:04:05 GMT-0700 (Mountain Standard Time)"
    parsedTime, err := time.Parse(layout, temp.Date)
    if err != nil {
        return err
    }

    // 赋值并转换日期为primitive.DateTime(对应MongoDB的ISODate)
    t.ID = temp.ID
    t.Category = temp.Category
    t.Amount = temp.Amount
    t.Owner = temp.Owner
    t.Date = primitive.NewDateTimeFromTime(parsedTime)

    return nil
}

之后绑定逻辑保持不变即可:

var transaction models.Transaction
if err := c.ShouldBindJSON(&transaction); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
}
// 插入MongoDB时,Date会自动以ISODate格式存储
createdTransaction, createErr := handler.collection.InsertOne(handler.ctx, transaction)

方法二:临时结构体中转+手动转换

如果不想修改原结构体的解析逻辑,可以通过临时结构体完成绑定后再手动转换日期:

// 定义临时结构体
type TempTx struct {
    ID       primitive.ObjectID `json:"id"`
    Category primitive.ObjectID `json:"category,omitempty"`
    Amount   string             `json:"amount" binding:"required"`
    Owner    primitive.ObjectID `json:"owner,omitempty"`
    Date     string             `json:"date"`
}

var tempTx TempTx
if err := c.ShouldBindJSON(&tempTx); err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
    return
}

// 解析日期
layout := "Mon Jan 02 2006 15:04:05 GMT-0700 (Mountain Standard Time)"
parsedTime, err := time.Parse(layout, tempTx.Date)
if err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "无效的日期格式"})
    return
}

// 转换为正式Transaction结构体
transaction := models.Transaction{
    ID:       tempTx.ID,
    Category: tempTx.Category,
    Amount:   tempTx.Amount,
    Owner:    tempTx.Owner,
    Date:     primitive.NewDateTimeFromTime(parsedTime),
}

// 插入MongoDB
createdTransaction, createErr := handler.collection.InsertOne(handler.ctx, transaction)

关键注意事项

  • 日期解析的layout必须与传入的日期格式完全匹配,注意占位符对应关系(比如02代表两位日期,15代表24小时制小时)。
  • primitive.NewDateTimeFromTime()会将time.Time转换为MongoDB的ISODate类型,插入后会以标准ISODate格式存储。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:45:46