在Go中编组和解组自定义日期格式

我认为许多人都会同意,几乎可以使用任何一种编程语言来处理日期都是令人难以置信的麻烦。日期和时间不是十进制的,时区-我的天哪,为什么它们不能只是整数-当然还有无数的日期和时间格式。您当然可以争辩说他们说有ISO 8601,还有什么需要傻瓜的,但是让我们面对现实吧-您多久遇到第三方API遵守此标准的要求了?我不知道事情如何发展,我希望他们能在评论中告诉我,但是在后苏联时代,情况是拥抱和哭泣。每个人都使用自己的方式(仅对他方便),时间和日期格式,并根据需要进行处理。


我将谈论自己的经验以及所找到的解决方案。


我面临的问题看起来还不错,我必须处理的API中的日期格式看起来像这样:YYYY-MM-DD hh:mm:ss看起来很正常,不是吗?


没有。


绝对不正常。


那些熟悉ISO 8601格式的人已经意识到了这一点。为了清楚起见:


package main

import (
    "encoding/json"
    "log"
    "time"
)

type Dated struct {
    DateTime time.Time
}

func main() {
    input := []byte("{\"datetime\": \"1900-01-01 12:00:04\"}")
    var d Dated
    err := json.Unmarshal(input, &d)
    if err != nil {
        log.Fatal(err)
    }
}

结果是什么?是的,错误是:


parsing time ""1900-01-01 12:00:04"" as ""2006-01-02T15:04:05Z07:00"": cannot parse " 12:00:04"" as "T"

这是合乎逻辑的,因为Go开箱
即用地可以解析的时间和日期格式数量有限


ANSIC       = "Mon Jan _2 15:04:05 2006"
UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
RFC822      = "02 Jan 06 15:04 MST"
RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
RFC3339     = "2006-01-02T15:04:05Z07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
Kitchen     = "3:04PM"
// Handy time stamps.
Stamp      = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano  = "Jan _2 15:04:05.000000000"

从这里:https : //golang.org/src/time/format.go


如您所见,格式YYYY-MM-DD hh:mm:ss不存在。好的,麻烦很明显,但是那该怎么办呢?


, , Go json.Unmarshall. — , JSON, , , UnmasrhallJSON,
.


, ,
, Unmarshaler, UnmasrhallJSON:


type CustomDate struct {
    time.Time
}

func (c *CustomDate) UnmarshalJSON(b []byte) (err error) {
    layout := "2006-01-02 15:04:05"

    s := strings.Trim(string(b), "\"") // remove quotes
    if s == "null" {
        return
    }
    c.Time, err = time.Parse(layout, s)
    return
}

type Dated struct {
    DateTime CustomDate
}

, , API, , , . :


package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strings"
    "time"
)

type CustomDate struct {
    time.Time
}

const layout = "2006-01-02 15:04:05"

func (c *CustomDate) UnmarshalJSON(b []byte) (err error) {
    s := strings.Trim(string(b), `"`) // remove quotes
    if s == "null" {
        return
    }
    c.Time, err = time.Parse(layout, s)
    return
}

func (c CustomDate) MarshalJSON() ([]byte, error) {
    if c.Time.IsZero() {
        return nil, nil
    }
    return []byte(fmt.Sprintf(`"%s"`, c.Time.Format(layout))), nil
}

type Dated struct {
    DateTime CustomDate
}

func main() {
    input := []byte("{\"datetime\": \"1900-01-01 12:00:04\"}")
    var d Dated
    err := json.Unmarshal(input, &d)
    if err != nil {
        log.Fatal(err)
    }
    log.Println("Unmarshal:")
    log.Println(d.DateTime)

    b, err := json.Marshal(d)
    if err != nil {
        log.Fatal(err)
    }
    log.Println("Marshal:")
    log.Println(string(b))
}

Marshal/Unmarshal. — MarchalJSON , UnmarshalJSON —

:


Unmarshal:
1900-01-01 12:00:04 +0000 UTC
Marshal:
{"DateTime":"1900-01-01T12:00:04Z"}

, , .



Go — , , /, , ; — .


如果您准备提供其他有趣的方式来解决此问题-我将很高兴在评论中看到它们。好吧,总而言之,我希望您少处理任何非标准格式的东西。


谢谢大家。


All Articles