Golang中自定义时间类型反序列化返回对象的实现方法

Golang中自定义时间类型反序列化返回对象的实现方法 大家好,

我是Go语言的新手,到目前为止我非常喜欢它!

我有一个实际的工作项目,用来学习这门语言,在过去的2天里我学到了很多新东西。然而,我在一个特定主题上遇到了困难:从XML文件中反序列化自定义时间属性。到目前为止,我已经实现了以下代码:

type Program struct {
    ...
	Timestamp     customTime `xml:"timestamp,attr"`
    ...
}

type customTime struct {
	Timestamp time.Time
}

func (c *customTime) UnmarshalXMLAttr(attr xml.Attr) error {
	date := attr.Value + " CET"
	parse, _ := time.Parse("2006-01-02T15:04:05 MST", date)
	*c = customTime{parse}
	return nil
}

这种方式某种程度上是可行的,然而,这导致时间戳在MongoDB中被保存为一个对象:

_id: ObjectId(235235235235)
timestamp: Object
  timestamp: 2020-02-04T17:46:37.000+00:00

这一切都说得通,但我不想要那个对象,我只希望时间戳作为第一个时间戳的值。我阅读了很多资料,但找不到实现这一目标所需的文档。

非常感谢任何帮助!

此致, Derk


更多关于Golang中自定义时间类型反序列化返回对象的实现方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

嗨,德克,

你的 XML 反序列化看起来是正确的。当你保存到 MongoDB 时,你是如何使用你的 customTime 类型的?

更多关于Golang中自定义时间类型反序列化返回对象的实现方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢您抽出时间回复!

我也尝试了那个方法(在发帖之后),我认为这让我走上了正确的轨道。然而,它的输出如下(注意 v.Timestamp):

DATE 2021-05-15
PARSE 2021-05-15 00:00:00 -0700 MST
{0 63756658800 0xc000052240}

我认为这可能和指针有关,但因为我来自 Python 和 JavaScript 背景,指针对我来说是个新概念(如果这确实是和指针有关的话)。

你好 Derk!

我也是 Go 语言的初学者,所以可能无法提供太多帮助,但我有一个想法或许能解决你的问题。

如果你不将 customTime 定义为结构体,而是直接定义为 time.Time 类型,也许就能避免在将数据存入 MongoDB 时产生额外的包装对象。

我想到的代码示例如下:

type Program struct {
	Timestamp customTime `xml:"timestamp,attr"`
}

type customTime time.Time

func (c *customTime) UnmarshalXMLAttr(attr xml.Attr) error {
	date := attr.Value
	fmt.Println("DATE", date)
	location, _ := time.LoadLocation("MST")
	parse, err := time.ParseInLocation("2006-01-02", date, location)
	if err != nil {
		panic(err)
	}
	fmt.Println("PARSE", parse)
	*c = customTime(parse)
	return nil
}

func main() {
	testXML := []byte(`<Program timestamp="2021-05-15"></Program>`)

	var v Program
	if err := xml.Unmarshal(testXML, &v); err != nil {
		panic(err)
	}

	fmt.Println(v.Timestamp)
}

最终我采用了:

			_, err = collection.InsertOne(ctx, bson.M{
			"guci":       notifyXml.Guci,
			"prid":       notifyXml.Prid,
			"pridexport": notifyXml.Pridexport,
			"titel":      notifyXml.Titel,
			"wsrid":      notifyXml.Wsrid,
			"type":       notifyXml.Type,
			"platform":   notifyXml.Platform,
			"puboptie": append(pubSlice, PubOptie{
				Puboptie:  notifyXml.Puboptie,
				Videofile: notifyXml.Videofile,
				CreatedAt: time.Now(),
			}),
			"timestamp": notifyXml.Timestamp.Timestamp,
			"starttijd": notifyXml.Timestamp.Timestamp,
			"eindtijd":  notifyXml.Timestamp.Timestamp.AddDate(0, 0, 7),
			"createdAt": time.Now(),
			"updatedAt": time.Now(),
		})

无论如何我都需要执行一些像 time.Now() 这样的操作,所以这个方法可行。

要实现自定义时间类型的反序列化,同时避免在MongoDB中保存为嵌套对象,你需要让customTime直接内嵌time.Time类型,而不是作为其字段。以下是修改后的实现:

type Program struct {
    // 其他字段...
    Timestamp customTime `xml:"timestamp,attr"`
}

type customTime struct {
    time.Time
}

func (c *customTime) UnmarshalXMLAttr(attr xml.Attr) error {
    // 添加时区信息
    date := attr.Value + " CET"
    parsed, err := time.Parse("2006-01-02T15:04:05 MST", date)
    if err != nil {
        return err
    }
    c.Time = parsed
    return nil
}

// 可选:实现MarshalXMLAttr用于序列化
func (c customTime) MarshalXMLAttr(name xml.Name) (xml.Attr, error) {
    return xml.Attr{
        Name:  name,
        Value: c.Format("2006-01-02T15:04:05 MST"),
    }, nil
}

这样修改后,customTime直接继承time.Time的所有方法,并且在MongoDB中会保存为简单的时间戳值,而不是嵌套对象。当保存到MongoDB时,会得到类似这样的结构:

_id: ObjectId(235235235235)
timestamp: 2020-02-04T17:46:37.000+00:00

关键点:

  1. 使用类型嵌入(time.Time)而不是字段
  2. 直接操作嵌入的time.Time字段
  3. 添加了错误处理,避免忽略解析错误
  4. 可选实现了序列化方法以保持双向兼容

这种实现方式既满足了XML反序列化的需求,又避免了在数据库中产生嵌套结构。

回到顶部