Membungkam dan menghapus format tanggal khusus di Go

Saya pikir banyak orang akan setuju bahwa bekerja dengan tanggal di hampir semua bahasa pemrograman adalah sakit kepala yang luar biasa. Tanggal dan waktu bukan desimal, zona waktu - Ya Tuhan, mengapa tidak bisa hanya bilangan bulat - dan tentu saja, format tanggal dan waktu yang tak terhitung jumlahnya. Anda dapat, tentu saja, berpendapat bahwa mereka mengatakan ada ISO 8601 dan apa lagi yang Anda butuhkan untuk dibodohi, tetapi mari kita hadapi itu, katakan saja - seberapa sering Anda menemui kepatuhan dengan standar ini di API pihak ketiga? Saya tidak tahu bagaimana keadaan di luar negeri dengan ini, saya berharap mereka akan memberi tahu saya di komentar, tetapi dalam ekspansi pasca-Soviet situasinya adalah pelukan dan tangisan. Masing-masing menggunakan sendiri, hanya nyaman untuknya, format waktu dan tanggal dan mengatasinya seperti yang Anda inginkan.


Saya akan berbicara tentang pengalaman saya sendiri dan tentang solusi yang ditemukan.


Masalah yang saya hadapi tidak terlihat begitu buruk, format tanggal di API yang harus saya tangani tampak seperti ini: YYYY-MM-DD hh: mm: ss . Sepertinya normal, bukan?


Tidak.


Benar-benar abnormal.


Mereka yang terbiasa dengan format ISO 8601 telah menyadari hal itu. Untuk kejelasan:


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

Akibat apa? Itu benar, kesalahannya adalah:


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

Yang logis, karena Go telah keluar dari kotak sejumlah waktu dan format tanggal
yang dapat diuraikan:


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"

Dari sini: https://golang.org/src/time/format.go


Seperti yang Anda lihat, formatnya YYYY-MM-DD hh:mm:sstidak ada. Oke, masalahnya jelas, tetapi apa yang harus dilakukan?


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


Jika Anda siap menawarkan cara menarik lainnya untuk menyelesaikan masalah ini - saya akan senang melihatnya di komentar. Kesimpulannya, saya ingin sedikit agar Anda tidak berurusan dengan format apa pun yang tidak standar.


Terimakasih untuk semua.


All Articles