简介

go 中使用 json.Unmarshal 转换结构体时,若结构体中有时间类型作为解析字段时,使用的是国际标准 RFC33392006-01-02T15:04:05Z07:00) 格式来作为默认格式进行解析的。
现前后端交互时间,有三种方式

  1. 前端自行做 RFC3339 的时间格式转换
  2. 后端自定义 MarshalJSONUnmarshalJSON 方法
  3. 前后端统一用时间戳进行交互(推荐这种方式


1. 前端的时间转换 RFC3339

标准格式日期转为 RFC3339

var toRFC3339 = function(date){
    let y = date.getFullYear()
    let m = date.getMonth()+1<10?'0'+(date.getMonth()+1):(date.getMonth()+1)
    let d = date.getDate()<10?'0'+date.getDate():date.getDate()
    let hh = date.getHours()<10?'0'+date.getHours():date.getHours();            
    let mm = date.getMinutes()<10?'0'+date.getMinutes():date.getMinutes()
    let ss = date.getSeconds()<10?'0'+date.getSeconds():date.getSeconds()
    var endDate = y +'-' + m + '-' + d + ' ' + hh + ':' + mm + ':' + ss
    endDate = endDate.replace(/\s+/g, 'T')+'+08:00'
    return endDate
}

RFC3339转为标准格式日期

var toTime = function(dateStr) {
    var date = new Date(dateStr).toJSON();
    return newDate=new Date(+new Date(date)+8*3600*1000).toISOString().replace(/T/g,' ').replace(/\.[\d]{3}Z/,'');
}


2. 后端做转换

自定义 time 类型,然后自己实现 jsonMarshalJSONUnmarshalJSON 方法。以下例子作参考:

package jsontest

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

type Time time.Time

const (
    timeFormart = "2006-01-02 15:04:05"
)

func (t *Time) UnmarshalJSON(data []byte) (err error) {
    now, err := time.ParseInLocation(`"`+timeFormart+`"`, string(data), time.Local)
    *t = Time(now)
    return
}

func (t Time) MarshalJSON() ([]byte, error) {
    b := make([]byte, 0, len(timeFormart)+2)
    b = append(b, '"')
    b = time.Time(t).AppendFormat(b, timeFormart)
    b = append(b, '"')
    return b, nil
}

func (t Time) String() string {
    return time.Time(t).Format(timeFormart)
}

type Person struct {
    Id       int64  `json:"id"`
    Name     string `json:"name"`
    Birthday Time   `json:"birthday"`
}

func TestTimeJson(t *testing.T) {
    now := Time(time.Now())
    t.Log(now)
    src := `{"id":5,"name":"xiaoming","birthday":"2016-06-30 16:09:51"}`
    p := new(Person)
    err := json.Unmarshal([]byte(src), p)
    if err != nil {
        t.Fatal(err)
    }
    t.Log(p)
    t.Log(time.Time(p.Birthday))
    js, _ := json.Marshal(p)
    t.Log(string(js))
}


3. 统一使用时间戳

go 获取时间戳(秒)

time.Now().Unix()

js 获取时间戳(毫秒)

var d = new Date()
d.getTime()  // 1627457656981 



go time 包源码查看

源代码在 src/time/time.go 文件中

UnmarshalJSON 方法

func (t *Time) UnmarshalJSON(data []byte) error {
	// Ignore null, like in the main JSON package.
	if string(data) == "null" {
		return nil
	}
	// Fractional seconds are handled implicitly by Parse.
	var err error
	*t, err = Parse(`"`+RFC3339+`"`, string(data))
	return err
}

time 包支持的其他日期格式

const (
	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"
)

小结

本篇的问题,主要是在前后端做交互时,接口调用报错,后发现 json 解析时间错误,前后端的时间格式不一致。
涉及时间的交互,推荐使用时间戳来进行交互,这样会避免很多问题。
最后还要提一下,jsdate.getTime() 获取到的默认时间戳是毫秒,而 gotime.Unix() 获取的默认为,这个在做前后端交互的时候一定要当心。

参考

GitHub 加速计划 / js / json
18
5
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:2 个月前 )
960b763e 5 个月前
8c391e04 8 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐