JohnWrensby
JohnWrensby

Reputation: 2842

Parse .Net JSON date with Go

How can I parse this .Net JSON date with Go? The value comes back unassigned. It appears to parse up to the date field.

package main

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

type MyStruct struct {
    FirstField string
    SomeTime time.Time
    LastField string
}

type MyStructSlice struct {
    MyStructs []MyStruct
}

func main() {
    var s MyStructSlice 
    str := `{"MyStructs":[{"FirstField":"123", "SomeTime":"\/Date(1432187580000-0500)\/", "LastField":"456"}]}`
    json.Unmarshal([]byte(str), &s)
    fmt.Println(s)
}

Go Playground

Upvotes: 1

Views: 975

Answers (3)

icza
icza

Reputation: 417512

First you model is wrong, it doesn't model the data structure in your JSON. It should be:

type Data struct {
    Data []MyStruct `json:"data`
}
type MyStruct struct {
    SomeTime string
}

It works with this, try it on the Go Playground.

Problem is that we still have the time as string.

Now if you want SomeTime to be time.Time, you need to parse it yourself, you can do it by implementing json.Unmarshaler:

type Data struct {
    Data []MyStruct `json:"data`
}

type MyStruct struct {
    SomeTime time.Time
}

func (m *MyStruct) UnmarshalJSON(data []byte) error {
    // First unmashal it into a string:
    ms := struct{ SomeTime string }{}
    if err := json.Unmarshal(data, &ms); err != nil {
        return err
    }

    s := ms.SomeTime

    // s is of format: "/Date(1432187580000-0500)/"
    // extract millis and time zone offset hours
    i1 := strings.Index(s, "(")
    i3 := strings.Index(s, ")")
    i2 := strings.Index(s, "-")
    if i2 < 0 {
        i2 = strings.Index(s, "+")
    }
    if i1 < 0 || i2 < 0 || i3 < 0 {
        return errors.New("Invalid format")
    }

    millis, err := strconv.ParseInt(s[i1+1:i2], 10, 64)
    if err != nil {
        return err
    }
    m.SomeTime = time.Unix(0, millis*1000000)

    // Apply timezone:
    zoneHours, err := strconv.ParseInt(s[i2:i3], 10, 64)
    if err != nil {
        return err
    }
    zone := time.FixedZone("something", int(zoneHours)*3600)
    m.SomeTime = m.SomeTime.In(zone)
    return nil
}

Try it on the Go Playground.

Upvotes: 0

Salvador Dali
Salvador Dali

Reputation: 222481

The value comes back unassigned for many reasons. First of all your MyStruct does not look right. Your JSON has data key as the parent key, which consists an array of objects.

But your struct for some reason does not even resembles this. It has to have Date as a field at least. So make your struct look like the json you are receiving.

Another thing is that your time.Time will not be able to parse this string: Date(1432187580000-0500) in a normal date.

P.S. now that you have updated your struct to normal way, you have to find a way to parse your strange sting to a date. If you have power over your .net application, I would rather recommend changing json to a normal timestamp or something that can be easily parsable.

If not, then you have to change SomeTime time.Time to SomeTime string and then parse string to a normal timestamp and then parse this timestamp to a date.

Upvotes: 0

kostya
kostya

Reputation: 9559

I am going to provide a few suggestions. You will have to write the code yourself though ;)

First of all is it possible to change .NET application that produced this JSON to generate something more parsable? If you make it output datetime in RFC3339 format (something like 1990-12-31T15:59:12-08:00) then go will automatically converts it to time.Time instance thanks to http://golang.org/pkg/time/#Time.UnmarshalJSON

If you cannot change the client then you will have to parse this date yourself:

  1. extract time part (1432187580000) from the string. this looks like number of milliseconds (ms) since UNIX epoch. You can convert it to time.Time instance using time.Unix(sec, nsec).

  2. (optional). The time that was created in the last step already accurately represent a point in time. However if you want to add the original timezone to it (e.g. to print it) you will need to:

Example: http://play.golang.org/p/Pkahyg2vZa

Upvotes: 1

Related Questions