Golang/Framework

[Gin] time Parsing 오류 -> 원하는 포맷으로 타임 바인딩하는 법

GenieLove! 2022. 11. 24. 23:51
728x90
반응형

time Parsing 오류

Gin Bind

func Test(c *Gin.Context) {
    var body Body
    if err := c.Bind(&body); err != nil {
        c.JSON(400, err)
        return
    }
    c.JSON(200, nil)
}
type Body sturct {
    Birthday time.Time `json:"birthday" time_format:"2006-01-02 15:04:05"`
}

위에처럼 Body 구조체가 있을 때 Gin에서 Binding 시 string으로 된 birthday를 전달하게 되면 아래 오류가 발생한다.

parsing time "\"2016-01-02 15:04:05\"" as "\"2006-01-02T15:04:05Z07:00\"": cannot parse " 15:04:05\"" as "T"

인터넷 검색 시 많이 나오는 time_format 태그는 form 형식으로 바인딩할 때 사용하는 태그이므로 json 형식을 바인딩할 때는 에러가 발생한다.

Time Overriding

1. Body에서 Birthday 타입을 아래와 같이 바꿔준다.

type Body sturct {
    Birthday NewTime `json:"birthday"`
}

2. UnmarshalJSON()을 오버라이딩 해주면 바인딩 시 기본 time 타입의 언마샬링이 아닌 오버라이딩한 함수로 작동되어 원하는 형식의 타임 포맷을 전달받을 수 있다.

3. MarshalJSON()을 오버라이딩해서 response 값도 원하는 포맷으로 할 수 있다. 처음엔 MarshalJSON도 포인터 리시버 함수로 작성했었는데 포인터 리시버 함수일 때는 작동하지 않는다.

type NewTime time.Time

func (n *NewTime) UnmarshalJSON(data []byte) (err error) {
    var s string
    err = json.Unmarshal(data, &s)
    if err != nil {
        return
    }
    
    location, err := time.LoadLocation("Asia/Seoul")
    
    if err != nil {
        return
    }
    
    /* location 사용 안 할 때는
    t, err := time.Parse("2006-01-02 15:04:05")
    
    if err != nil {
        return
    }
    
    t, err := time.ParseInLocation("2006-01-02 15:04:05", s, location)
    */
    
    *n = NewTime(t)
    return
}

func (n NewTime) MarshalJSON() ([]byte, error) {
    t := time.Time(n)
    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("2006-01-02 15:04:05")+2)
	b = append(b, '"')
    b = t.AppendFormat(b, "2006-01-02 15:04:05")
    b = append(b, '"')
    return b, nil
}
728x90
반응형