如何在golang中将时间字符串解析为time.Time类型?

huangapple go评论74阅读模式
英文:

How to unmarshall time string into time.Time in golang?

问题

我正在使用JOIN、CONCAT、GROUP_CONCAT和JSON_OBJECT从多个表中读取数据。使用gorm将数据读入下面提到的模型中。

type OrgUserDisPublisherData struct {
    Disciplines datatypes.JSON `json:"disciplines" example:"[]"`
    User        datatypes.JSON `json:"user"`
}

这个过程已经成功完成。但是当我尝试将OrgUserDisPublisherData.Disciplines反序列化为另一个具有time.Time数据类型的结构体时,我遇到了以下错误:parsing time "\"2022-11-03 07:08:09.000000\"" as "\"2006-01-02T15:04:05Z07:00\"": cannot parse " 07:08:09.000000\"" as "T"

用于反序列化的最终模型如下:

type Discipline struct {
    Name              string    `json:"name"`
    Code              string    `json:"code"`
    IsPrimary         uint      `json:"isPrimary"`
    IsAligned         uint      `json:"isAligned"`
    IsTrainingFaculty uint      `json:"isTrainingFaculty"`
    AlignmentDate     time.Time `json:"alignmentDate"`
    UnalignmentDate   time.Time `json:"UnalignmentDate"`
    ExpiryDate        time.Time `json:"expiryDate"`
    ExternalId        string    `json:"externalId"`
    Status            string    `json:"status"`
    CreatedAt         time.Time `json:"createdAt"`
    UpdatedAt         time.Time `json:"updatedAt"`
}

同时,在向表中插入数据时,使用了相同的模型,但没有抛出与时间相关的任何错误。无论时间属性中存在什么数据,我该如何处理反序列化时的时间问题?

英文:

I am reading data from multiple tables using JOIN, CONCAT, GROUP_CONCAT, JSON_OBJECT. The data is read into the below mentioned model using gorm.

type OrgUserDisPublisherData struct {
	Disciplines datatypes.JSON `json:"disciplines" example:"[]"`
	User        datatypes.JSON `json:"user"`
}

This process is successfully completed. But then when I try to unmarshal the OrgUserDisPublisherData.Disciplines into another struct which has time.Time datatypes. I am getting the following error parsing time "\"2022-11-03 07:08:09.000000\"" as "\"2006-01-02T15:04:05Z07:00\"": cannot parse " 07:08:09.000000\"" as "T"

Final model used for unmarshalling

type Discipline struct {
		Name              string    `json:"name"`
		Code              string    `json:"code"`
		IsPrimary         uint      `json:"isPrimary"`
		IsAligned         uint      `json:"isAligned"`
		IsTrainingFaculty uint      `json:"isTrainingFaculty"`
		AlignmentDate     time.Time `json:"alignmentDate"`
		UnalignmentDate   time.Time `json:"UnalignmentDate"`
		ExpiryDate        time.Time `json:"expiryDate"`
		ExternalId        string    `json:"externalId"`
		Status            string    `json:"status"`
		CreatedAt         time.Time `json:"createdAt"`
		UpdatedAt         time.Time `json:"updatedAt"`
	}

At the same time, while inserting data into the tables the same model was used and it does not throw any error related to time.
How can I handle time while unmarshalling, irrespective of the data that is present against the time property?

答案1

得分: 1

这里的问题是,GoLang结构体中日期/时间类型的默认JSON编组行为是使用ISO8601格式的日期/时间字符串。

这可以通过错误消息中的格式字符串来识别,其中日期和时间之间有一个T分隔符和时区后缀。你的Discipline JSON字符串中的值不符合这个格式,既没有T分隔符,也没有任何时区。因此出现了错误。

如果你可以影响gorm生成的JSON字符串的格式(我不熟悉这个,所以无法确定你是否可以以及如何这样做),那么最简单的解决方案是确保你的JSON字符串时间字段格式化为ISO8601/RFC3339字符串。

如果你无法控制这一点,那么你有两个选择:

  1. 通过一个中间的map[string]any对JSON进行预处理,并重新格式化相应的字段。如果gorm的格式化至少是一致的,那么这可能很容易,只需在空格上分割字符串,从时间中删除最后的3位小数,添加适当的时区(如果时间是UTC,则只需添加Z),然后使用T分隔符重新组装。

  2. 使用具有正确处理gorm格式化值的json.Marshaller实现的自定义时间类型(在编组时仍然需要知道适用于持久化值的时区,并在编组时正确应用该时区)。

这两种方法都容易受到gorm日期/时间变量格式化的更改和误用的影响(在选项1中未进行预处理,以及在选项2中错误地使用time.Time而不是自定义类型)。

因此,如果可能的话,修改gorm的格式化输出将是我首选的方法。

英文:

The problem here is that the default JSON marshalling behaviour for date/time types in GoLang structs is to use ISO8601 formatted date/time strings.

This is identified by the format string in the error message with the T separator between date and time and time-zone suffix. The values in your Discipline JSON string don't conform to this format, lacking both the T separator and any time-zone. Hence the error.

If you can influence the formatting of the JSON string produced by gorm, (not something I'm familiar with so cannot say whether you can or how to do so), then the simplest solution would be to ensure that your JSON string time fields are formatted as ISO8601/RFC3339 strings.

If you have no control over that, then you have two options:

  1. Implement some pre-processing of the JSON via an intermediate map[string]any and reformat the appropriate fields. If the gorm formatting is at least consistent then this could be as easy as splitting the string on the space, remove the final 3dps from the time, append an appropriate timezone (or just Z if the times are UTC) then re-assemble with a T separator.

  2. Use a custom time type with a json.Marshaller implementation that works correctly with the gorm formatted values (you still need to know what time zone applies to the persisted values and apply that correctly when marshalling).

Both of these are vulnerable to a change in the gorm formatting of date/time variables and mis-use (failing to pre-process in the case of Option #1 and mistakenly using time.Time rather than the custom type in the case of Option #2).

For this reason, modifying the formatted output from gorm would be the preferred approach for me, if it is possible.

答案2

得分: 0

最快的解决方案是在从数据库读取数据/值时进行格式化,正如 @Deltics 建议的那样。

在从数据库查询数据时,使用 DATE_FORMAT() 函数将数据格式化为 go/json 所需的格式:

DATE_FORMAT(actual_data, '%Y-%m-%dT%TZ')
英文:

The quickest solution was to format the data/value while reading it from DB, as suggested by @Deltics.

While querying the data from the DB, using the DATE_FORMAT() I am formatting the data into the format required by go/json

DATE_FORMAT(actual_data, '%Y-%m-%dT%TZ')

huangapple
  • 本文由 发表于 2022年11月13日 23:24:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/74422263.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定