gocustom-type

Format of date changes when using it via custom types


I'm very new to golang and still struggling with many things.

When implementing custom type like this type Date time.Time, an defining a method to marshal/unmarshal dates that come in "2006-01-02" format (from a JSON file and from a POST API request), the final way in which dates are stored in the struct is:

{wall:0 ext:63776764800 loc:<nil>}

Can someone help me understand why that format (instead of regular time.Time) since the custom type Date is capitalized, hence exported?

Here an implementation (link to playground below the code):

package main

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

const sample = `{
    "ID": "1",
    "ticker": "S30J2",
    "issueDate": "2022-01-31",
    "maturity": "2023-06-30",
    "coupon": 0,
    "cashFlow": [
        {   "date": "2022-06-30",
            "rate": 0,
            "amortization": 1,
            "residual": 0,
            "amount": 50},
            {
            "date": "2023-06-30",
            "rate": 0,
            "amortization": 1,
            "residual": 0,
            "amount": 50}
    ]
}`

type Date time.Time

func (d Date) MarshalJSON() ([]byte, error) {
    return []byte(time.Time(d).Format("2006-1-2")), nil
}

func (d *Date) UnmarshalJSON(b []byte) error {
    // Disregard leading and trailing "
    t, err := time.Parse("2006-1-2", string(b[1:len(b)-2]))
    if err != nil {
        return err
    }
    *d = Date(t)
    return nil
}

type Flujo struct {
    Date     Date
    Rate     float64
    Amort    float64
    Residual float64
    Amount   float64
}
type Bond struct {
    ID        string
    Ticker    string
    IssueDate Date
    Maturity  Date
    Coupon    float64
    Cashflow  []Flujo
}

func main() {
    var b Bond
    if err := json.Unmarshal([]byte(sample), &b); err != nil {
        log.Fatalf("%s", err)
    }
    fmt.Printf("%+v\n", b.IssueDate)
    // I need to wrap it via Format.
    fmt.Println("Fecha: ", time.Time(b.IssueDate).Format("2006-01-02"))

}

Here the working example: https://go.dev/play/p/YddzXA9PQdP

Thanks for the help and understanding.


Solution

  • The type Date is a new named type distinct from time.Time, and it does not have the methods defined for time.Time. The marshal/unmarshal methods work just fine, but fmt.Print family of function use the Stringer interface if one exists. Thus if you declare:

    func (d Date) String() string {
        x, _ := d.MarshalJSON()
        return string(x)
    }
    

    It will print correctly.