Go 解决时间序列化

Go时间类型序列化反序列化

系统时间类型

定义结构体

type Person struct {
   Birthday time.Time
   Name string
}

序列化

func TestMarshal(t *testing.T)  {
	person := Person{
		Birthday: time.Now(),
		Name: "leon",
	}
	data, err := json.Marshal(&person)

	if err != nil {
		fmt.Println("Marshal Error:",err)
		return
	}
	fmt.Println(string(data))
	// {"Birthday":"2021-12-04T19:57:00.291554+08:00","Name":"leon"}
}
  • 可以看到序列化后的时间格式是2021-12-04T19:57:00.291554+08:00 这样的

反序列化

func  TestUnmarshal(t *testing.T)  {

	var str = `{"birthday":"2021-12-04T19:57:00.291554+08:00", "name":"leon"}`
	var person Person
	if err := json.Unmarshal([]byte(str), &person); err != nil{
		fmt.Println("Unmarshal Error:",err)
		return
	}
	fmt.Println(person)
	// {2021-12-04 19:57:00.291554 +0800 CST leon}

}

  • 在定义json字符串时,时间是2021-12-04T19:57:00.291554+08:00 可以正常序列化

  • 如果想要 2021-12-04 19:57:00 这种格式的时间,系统库time.Time就无法做到,如果前端传入的参数是这种格式的会出现解析失败的情况,看下列

    func  TestUnmarshal2(t *testing.T)  {
    
    	var str = `{"birthday":"2021-12-04 19:57:00", "name":"leon"}`
    	var person Person
    	if err := json.Unmarshal([]byte(str), &person); err != nil{
    		fmt.Println("Unmarshal Error:",err)
    		return
    	}
    	fmt.Println(person)
    	// Unmarshal Error: parsing time "\"2021-12-04 19:57:00\"" as "\"2006-01-02T15:04:05Z07:00\"": cannot parse " 19:57:00\"" as "T"
    
    }
    
    
    • 解析失败
  • 可以自定义进行时间序列化

自定义时间类型

定义类型

type LocalTime time.Time
  • 定义了一种类型 LocalTime 其真实类型是time.Time

  • 如果直接使用 LocalTime 类型来定义时间,会出现问题,也是无法进行序列化和反序列化,因为 time.Time 实现了 UnmarshalerMarshaler 接口中的方法,可以正常序列化操作。

  • 所以我们自定义的LocalTime 类型 也要实现 UnmarshalerMarshaler 接口中的方法

  • 可以先观察一下 time.Time 是如何实现的

    func (t Time) MarshalJSON() ([]byte, error) {
    	if y := t.Year(); y < 0 || y >= 10000 {
    		// RFC 3339 is clear that years are 4 digits exactly.
    		// See golang.org/issue/4556#c15 for more discussion.
    		return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
    	}
    
    	b := make([]byte, 0, len(RFC3339Nano)+2)
    	b = append(b, '"')
    	b = t.AppendFormat(b, RFC3339Nano)
    	b = append(b, '"')
    	return b, nil
    }
    
    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
    }
    
  • 另外需要重点注意,也需要实现系统的 String() string 否则反序列化读取数据是,解析出来的数据是二进制数据,不是正确的类型,可以参考一下 time.Time 是如何实现的

    func (t Time) String() string {
    	s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST")
    
    	// Format monotonic clock reading as m=±ddd.nnnnnnnnn.
    	if t.wall&hasMonotonic != 0 {
    		m2 := uint64(t.ext)
    		sign := byte('+')
    		if t.ext < 0 {
    			sign = '-'
    			m2 = -m2
    		}
    		m1, m2 := m2/1e9, m2%1e9
    		m0, m1 := m1/1e9, m1%1e9
    		var buf []byte
    		buf = append(buf, " m="...)
    		buf = append(buf, sign)
    		wid := 0
    		if m0 != 0 {
    			buf = appendInt(buf, int(m0), 0)
    			wid = 9
    		}
    		buf = appendInt(buf, int(m1), wid)
    		buf = append(buf, '.')
    		buf = appendInt(buf, int(m2), 9)
    		s += string(buf)
    	}
    	return s
    }
    
    
    • 注意 方法中的 s := t.Format("2006-01-02 15:04:05.999999999 -0700 MST") 代码。

总结

  • 自定义需要实现以下的方法

    String() string
    MarshalJSON() ([]byte, error)
    UnmarshalJSON(data []byte) error
    

定义结构体

// 定义格式化样式
const (
	DefaultTimeFormat = "2006-01-02 15:04:05"
)

type Person struct {
	Birthday LocalTime `json:"birthday"`
	Name string `json:"name"`
}

序列化

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

反序列化

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

实现String() string

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

测试

func TestDate(t *testing.T) {

	// 序列化
	var p = Person{Name: "leon", Birthday: LocalTime(time.Now())}
   	data, err := json.Marshal(&p)
	if err != nil {
		fmt.Println("marshal err", err)
		return
	}
	fmt.Println(string(data))


	// 反序列化
	src := []byte(`{"birthday":"2020-05-26 20:20:44","name":"leon"}`)
	var pp Person
	json.Unmarshal(src,&pp)
	fmt.Println(pp)

}
{"birthday":"2021-12-04 20:32:26","name":"leon"}
{2020-05-26 20:20:44 leon}
posted @ 2021-12-04 20:35  LeonDai  阅读(677)  评论(0)    收藏  举报