Benutzerdefinierte Datumsformate in Go

Ich denke, viele werden zustimmen, dass die Arbeit mit Daten in fast jeder Programmiersprache unglaubliche Kopfschmerzen bereitet. Datum und Uhrzeit sind keine Dezimalstellen, Zeitzonen - mein Gott, warum können sie nicht nur ganze Zahlen sein - und natürlich unzählige Formate von Datum und Uhrzeit. Sie können natürlich argumentieren, dass es ISO 8601 gibt und wofür Sie sonst noch einen Narren brauchen, aber seien wir ehrlich, sagen wir mal - wie oft haben Sie die Einhaltung dieses Standards in APIs von Drittanbietern festgestellt? Ich weiß nicht, wie es damit im Ausland läuft, ich hoffe, sie werden es mir in den Kommentaren sagen, aber in den postsowjetischen Weiten ist die Situation zu umarmen und zu weinen. Jeder verwendet sein eigenes, nur für ihn geeignetes Format für Uhrzeit und Datum und geht damit um, wie Sie möchten.


Ich werde über meine eigenen Erfahrungen und die gefundene Lösung sprechen.


Das Problem, mit dem ich konfrontiert war, sah nicht so schlimm aus. Das Datumsformat in der API, mit dem ich mich befassen musste, sah folgendermaßen aus: JJJJ-MM-TT hh: mm: ss . Sieht normal aus, nicht wahr?


Nein.


Absolut abnormal.


Diejenigen, die mit dem ISO 8601-Format vertraut sind, haben den Haken bereits erkannt. Zur Klarheit:


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)
    }
}

Als Ergebnis von was? Das stimmt, der Fehler ist:


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

Was logisch ist, da Go eine begrenzte Anzahl von Zeit- und Datumsformaten hat
, die analysiert werden können:


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"

Von hier aus: https://golang.org/src/time/format.go


Wie Sie sehen können, ist das Format YYYY-MM-DD hh:mm:ssnicht vorhanden. Okay, das Problem ist klar, aber was tun?


, , 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 — , , /, , ; — .


Wenn Sie bereit sind, andere interessante Möglichkeiten zur Lösung dieses Problems anzubieten, freue ich mich, diese in den Kommentaren zu sehen. Abschließend möchte ich Ihnen weniger wünschen, dass Sie sich mit nicht standardmäßigen Formaten von irgendetwas befassen.


Danke an alle.


All Articles