在Golang中完全解析时间戳

13

我正在尝试制作一个简单的工具,它可以解析文件中以JSON格式编写的行,并在数据库中执行 INSERT 操作。

我有一个结构体,它看起来像这样:

type DataBlob struct {
  ....
  Datetime time.Time `json:"datetime, string"`
  ....
}

并解析像这样的代码:

scanner := bufio.NewScanner(file)
// Loop through all lines in the file
for scanner.Scan() {
    var t DataBlob

    // Decode the line, parse the JSON
    dec := json.NewDecoder(strings.NewReader(scanner.Text()))
    if err := dec.Decode(&t);
    err != nil {
        panic(err)
    }

    // Perform the database operation
    executionString: = "INSERT INTO observations (datetime) VALUES ($1)"
    _, err := db.Exec(executionString, t.Datetime)
    if err != nil {
        panic(err)
    }
}

我的JSON文件有多行,每一行都包含一个类似于下面这样的datetime值:
{ "datetime": 1465793854 }

当将datetime格式化为Unix时间戳时,编组器会抱怨:

panic: parsing time "1465793854" as ""2006-01-02T15:04:05Z07:00"": cannot parse "1465793854" as """

在生成JSON的脚本(也是用Golang编写)中,我尝试简单地打印Time.time类型的字符串表示形式,产生了以下结果:
{ "datetime": "2016-06-13 00:23:34 -0400 EDT" }

当我进行解析时,编组程序会抱怨这一点:
panic: parsing time ""2016-06-13 00:23:34 -0400 EDT"" as ""2006-01-02T15:04:05Z07:00"": cannot parse " 00:23:34 -0400 EDT"" as "T"

如果我将这个时间戳(看起来很标准)也视为字符串并避免编组问题,当我尝试执行插入操作时,Postgres会抱怨:
panic: pq: invalid input syntax for type timestamp: "2016-06-13 00:23:34 -0400 EDT"

这令人沮丧的原因有很多,但主要是因为如果我序列化了一个Time.time类型,我认为它应该在处理的另一端仍然能够被理解。

我该如何解析这个时间戳以执行数据库插入操作呢?对于问题的长度请谅解,并感谢您的帮助!

2个回答

12

JSON反序列化time.Time期望日期字符串符合RFC 3339格式。

因此,在生成JSON的golang程序中,不要仅仅打印time.Time值,而是使用Format以RFC 3339格式打印它。

t.Format(time.RFC3339)

如果我序列化一个Time.time类型,我认为在处理的另一侧仍应该能够理解它。
如果您使用了 Marshaller接口进行序列化,则确实会以RFC 3339格式输出日期。因此,处理的另一侧将理解它。所以您也可以这样做。
d := DataBlob{Datetime: t}
enc := json.NewEncoder(fileWriter)
enc.Encode(d)

如果您无法控制JSON输入,那么该怎么办呢?有什么解决方案吗? - TecHunter
@techunter 一个自定义的反序列化程序。 - Aruna Herath

5

如果需要使用时间类型进行自定义反序列化,您需要创建自己的类型并实现UnmarshalJSON方法。以下是一个示例:

type Timestamp struct {
    time.Time
}

// UnmarshalJSON decodes an int64 timestamp into a time.Time object
func (p *Timestamp) UnmarshalJSON(bytes []byte) error {
    // 1. Decode the bytes into an int64
    var raw int64
    err := json.Unmarshal(bytes, &raw)

    if err != nil {
        fmt.Printf("error decoding timestamp: %s\n", err)
        return err
    }

    // 2. Parse the unix timestamp
    p.Time = time.Unix(raw, 0)
    return nil
}

然后在您的结构体中使用该类型:

type DataBlob struct {
  ....
  Datetime Timestamp `json:"datetime"`
  ....
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接