dotws86260
dotws86260
2019-02-28 08:50

解析PostgreSQL TIMESTAMP类型的值时出现问题

  • IT行业问题
  • 计算机技术
  • it技术
  • 编程语言问答
  • 互联网问答
已采纳

In PostgreSQL, I have table called surveys.

CREATE TABLE SURVEYS(
  SURVEY_ID UUID PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
  SURVEY_NAME VARCHAR NOT NULL,
  SURVEY_DESCRIPTION TEXT,
  START_PERIOD TIMESTAMP,
  END_PERIOD TIMESTAMP
);

As you can see only SURVEY_ID and SURVEY_NAME columns are NOT NULL.

In Go, I want to create new entry in that table by POST request. I send JSON object like this:

{
    "survey_name": "NAME",
    "survey_description": "DESCRIPTION",
    "start_period": "2019-01-01 00:00:00",
    "end_period": "2019-02-28 23:59:59"
}

Unfortunatly it raise strange ERROR:

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

Where I make mistake and how to fix my problem?

models/surveys.go:

import (
    "database/sql"
    "time"
)

type NullTime struct {
    time.Time
    Valid bool
}

type Survey struct {
    ID int `json:"survey_id"`
    Name string `json:"survey_name"`
    Description sql.NullString `json:"survey_description"`
    StartPeriod NullTime `json:"start_period"`
    EndPeriod NullTime `json:"end_period"`
}

controllers/surveys.go:

var CreateSurvey = func(responseWriter http.ResponseWriter, request *http.Request) {
    // Initialize variables.
    survey := models.Survey{}
    var err error

    // The decoder introduces its own buffering and may read data from argument beyond the JSON values requested.
    err = json.NewDecoder(request.Body).Decode(&survey)
    if err != nil {
        log.Println(err)
        utils.ResponseWithError(responseWriter, http.StatusInternalServerError, err.Error())
        return
    }
    defer request.Body.Close()

    // Execute INSERT SQL statement.
    _, err = database.DB.Exec("INSERT INTO surveys (survey_name, survey_description, start_period, end_period) VALUES ($1, $2, $3, $4);", survey.Name, survey.Description, survey.StartPeriod, survey.EndPeriod)

    // Shape the response depending on the result of the previous command.
    if err != nil {
        log.Println(err)
        utils.ResponseWithError(responseWriter, http.StatusInternalServerError, err.Error())
        return
    }
    utils.ResponseWithSuccess(responseWriter, http.StatusCreated, "The new entry successfully created.")
}
  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • dongliao1949 dongliao1949 2年前

    The error already says what is wrong:

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

    You are passing "2019-01-01 00:00:00" while it expects a different time format, namely RFC3339 (UnmarshalJSON's default).

    To solve this, you either want to pass the time in the expected format "2019-01-01T00:00:00Z00:00" or define your own type CustomTime like this:

    const timeFormat = "2006-01-02 15:04:05"
    
    type CustomTime time.Time
    
    func (ct *CustomTime) UnmarshalJSON(data []byte) error {
        newTime, err := time.Parse(timeFormat, strings.Trim(string(data), "\""))
        if err != nil {
            return err
        }
    
        *ct = CustomTime(newTime)
        return nil
    }
    
    func (ct *CustomTime) MarshalJSON() ([]byte, error) {
        return []byte(fmt.Sprintf("%q", time.Time(*ct).Format(timeFormat))), nil
    }
    

    Careful, you might also need to implement the Valuer and the Scanner interfaces for the time to be parsed in and out of the database, something like the following:

    func (ct CustomTime) Value() (driver.Value, error) {
        return time.Time(ct), nil
    }
    
    func (ct *CustomTime) Scan(src interface{}) error {
        if val, ok := src.(time.Time); ok {
            *ct = CustomTime(val)
        } else {
            return errors.New("time Scanner passed a non-time object")
        }
    
        return nil
    }
    

    Go Playground example.

    点赞 评论 复制链接分享

为你推荐