Skip to content

Instantly share code, notes, and snippets.

@skplunkerin
Last active August 3, 2020 14:24
Show Gist options
  • Save skplunkerin/4b3edb1e95fc0e2091b655ce7e50640f to your computer and use it in GitHub Desktop.
Save skplunkerin/4b3edb1e95fc0e2091b655ce7e50640f to your computer and use it in GitHub Desktop.
go golang custom unmarshal json string time

Strings in JSON Unmarshal

Quick note on this. JSON will add extra wrapping " quotes to strings which can really mess with you.

How to catch and remove the extra wrapping "'s:

example playground code

// UnmarshalJSON scrubs out whitespace from a valid json string, if any.
func (ss *ScrubString) UnmarshalJSON(data []byte) error {
	ns := string(data)
	// Check if we don't have a blank "\"\"" string.
	if len(ns) > 2 && ns[0] != '"' && ns[len(ns)] != '"' {
		*ss = ""
		return nil
	}
	// Remove the extra quotes.
	ns, err := strconv.Unquote(ns)
	if err != nil {
		return err
	}
	// Remove left/right whitespace.
	*ss = ScrubString(strings.TrimSpace(ns))
	return nil
}

Simple solution

Add custom type. Go Playground

package main

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

// Company struct
type Company struct {
	CompanyName string `json:"company_name"`
	ID          int    `json:"id"`
}

type MyTime struct {
	time.Time
}

func (m *MyTime) UnmarshalJSON(b []byte) error {
	// Ignore null, like in the main JSON package.
	if string(b) == "null" {
		return nil
	}

	// Fractional seconds are handled implicitly by Parse.
	var err error

	m.Time, err = time.Parse(`"2006-01-02T15:04:05.000-0700"`, string(b))
	return err
}

// ContactPointer struct
type ContactPointer struct {
	Company *Company `json:"company,omitempty"`
	DateCreated MyTime `json:"date_created"`
}

func main() {
	contactResponseWV := []byte(`{"date_created": "2019-12-18T01:23:35.000+0000", "company":null}`)

	// With Value
	wv := ContactPointer{}
	if err := json.Unmarshal(contactResponseWV, &wv); err != nil {
		panic(err)
	}

	fmt.Printf("DateCreated: %+v", wv.DateCreated)

}

Customized solution

Add custom type, with extra formatting. Go Playground

package main

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

// Company struct
type Company struct {
	CompanyName string `json:"company_name"`
	ID          int    `json:"id"`
}

type JSONTime struct {
	time.Time

	format string
}

func NewJSONTime(format string) JSONTime {
	return JSONTime{
		format: format,
	}
}

func (j *JSONTime) UnmarshalJSON(b []byte) error {
	// Ignore null, like in the main JSON package.
	if string(b) == "null" {
		return nil
	}

	// Fractional seconds are handled implicitly by Parse.
	var err error

	if j.format == "" {
		j.format = time.RFC3339
	}

	j.Time, err = time.Parse(`"`+j.format+`"`, string(b))
	return err
}

// ContactPointer struct
type ContactPointer struct {
	Company *Company `json:"company,omitempty"`

	// TODO: get time.Time to work... but how to convert the JSON string to time?
	DateCreated JSONTime `json:"date_created"`

	//DateCreated string `json:"date_created"`
}

func main() {
	contactResponseWV := []byte(`{"date_created": "2019-12-18T01:23:35.000+0000", "company":null}`)

	// With Value
	wv := ContactPointer{
		DateCreated: NewJSONTime("2006-01-02T15:04:05.000-0700"),
	}
	if err := json.Unmarshal(contactResponseWV, &wv); err != nil {
		panic(err)
	}

	fmt.Printf("DateCreated: %+v", wv.DateCreated)

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment