Search code examples
htmldatedatetimegogo-gorm

How to convert HTML DateTime to Golang Time object


I am beginner at golang. I am trying to take input from HTML input type date

<input type="date" id="birthDate" name="BirthDate" required placeholder="YYYY-MM-DD">

and post this create method

func (c *customerController) CreateCustomer(ctx *gin.Context) {
    var customer Customer
    if err := ctx.ShouldBindJSON(&customer); err != nil {
        ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    if err := c.service.CreateCustomer(customer); err != nil {
        ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create customer"})
        return
    }

    ctx.Status(http.StatusOK)
}

Customer object:

    type Customer struct {
    ID        uint      `gorm:"primarykey"`
    FirstName string    `gorm:"type:varchar(100);not null"`
    LastName  string    `gorm:"type:varchar(100);not null"`
    BirthDate time.Time `gorm:"not null"`
    Gender    string    `gorm:"type:varchar(6);not null"`
    Email     string    `gorm:"type:varchar(100);not null;unique"`
    Address   string    `gorm:"type:varchar(200)"`
}

When I try to add new Customer I get Http Error 400 because HTML date type is not match to golang Time object. And error body is {"error":"parsing time \"2014-05-05\" as \"2006-01-02T15:04:05Z07:00\": cannot parse \"\" as \"T\""} How can I solve this problem? Thanks in advance


Solution

  • I get Http Error 400 because HTML date type is not match to golang Time object.

    Please avoid thinking the issue like this.

    The real issue is that:

    1. On the client side, the parsed value of an <input type="date"> element is always formatted as yyyy-mm-dd (See value of <input type="date">).
    2. On the server side, ctx.ShouldBindJSON uses the encoding/json package to unmarshal the request, which uses (*Time).UnmarshalJSON to unmarshal a time into a time.Time object. (*Time).UnmarshalJSON requires that the time must be a quoted string in the RFC 3339 format (namely, 2006-01-02T15:04:05Z07:00) (See (*Time).UnmarshalJSON).

    The value in the format yyyy-mm-dd does not satisfy 2006-01-02T15:04:05Z07:00, that's why it failed.

    To address the issue, you can either transform the value into RFC 3339 format on the client side, or implement the json.Unmarshaler interface to support yyyy-mm-dd on the server side.

    There is a proposal to support struct tag for time.Format, which if implemented, would make it easy to handle this case. The proposal also shows how to workaround the issue as of now.

    The last note is, in a real world application, you should define what BirthDate time.Time means. For example, imaging a user in the time zone +07:00 said his birth date is 1990-05-21, and the value is stored to the database as 1990-05-20T17:00:00Z. Later another user loads this user's profile in time zone -03:00. What will you display on the page?