Golang gorm时间数据类型转换

huangapple go评论78阅读模式
英文:

Golang gorm time data type conversion

问题

情况:

我正在使用一个 postgres 数据库,并且有以下的结构:

type Building struct {
    ID        int       `json:"id,omitempty"`
    Name      string    `gorm:"size:255" json:"name,omitempty"`
    Lon       string    `gorm:"size:64" json:"lon,omitempty"`
    Lat       string    `gorm:"size:64" json:"lat,omitempty"`
    StartTime time.Time `gorm:"type:time" json:"start_time,omitempty"`
    EndTime   time.Time `gorm:"type:time" json:"end_time,omitempty"`
}

问题:

然而,当我尝试将这个结构体插入数据库时,出现了以下错误:

将时间“10:00:00”解析为“2006-01-02T15:04:05Z07:00”时出错:无法将“0:00”解析为“2006”。

可能是因为它没有将 StartTimeEndTime 字段识别为 Time 类型,而是使用了 Timestamp 类型。我该如何指定这些字段的类型为 Time

附加信息:

以下代码片段展示了我创建 Building 的代码:

if err = db.Create(&building).Error; err != nil {
    return database.InsertResult{}, err
}

Building 表的 SQL 代码如下:

DROP TABLE IF EXISTS building CASCADE;
CREATE TABLE building(
  id SERIAL,
  name VARCHAR(255) NOT NULL ,
  lon VARCHAR(31) NOT NULL ,
  lat VARCHAR(31) NOT NULL ,
  start_time TIME NOT NULL ,
  end_time TIME NOT NULL ,
  PRIMARY KEY (id)
);
英文:

Situation:

I'm using a postgres database and have the following struct:

type Building struct {
ID        int `json:"id,omitempty"`
Name      string `gorm:"size:255" json:"name,omitempty"`
Lon       string `gorm:"size:64" json:"lon,omitempty"`
Lat       string `gorm:"size:64" json:"lat,omitempty"`
StartTime time.Time `gorm:"type:time" json:"start_time,omitempty"`
EndTime   time.Time `gorm:"type:time" json:"end_time,omitempty"`
}

Problem:

However, when I try to insert this struct into the database, the following error occurs:

> parsing time ""10:00:00"" as ""2006-01-02T15:04:05Z07:00"": cannot
> parse "0:00"" as "2006""}.

Probably, it doesn't recognize the StartTime and EndTime fields as Time type and uses Timestamp instead. How can I specify that these fields are of the type Time?

Additional information

The following code snippet shows my Building creation:

if err = db.Create(&building).Error; err != nil {
    return database.InsertResult{}, err
}

The SQL code of the Building table is as follows:

DROP TABLE IF EXISTS building CASCADE;
CREATE TABLE building(
  id SERIAL,
  name VARCHAR(255) NOT NULL ,
  lon VARCHAR(31) NOT NULL ,
  lat VARCHAR(31) NOT NULL ,
  start_time TIME NOT NULL ,
  end_time TIME NOT NULL ,
  PRIMARY KEY (id)
);

答案1

得分: 7

gorm不直接支持TIME类型,但你可以创建自己的类型,并实现sql.Scannerdriver.Valuer接口,以便能够从数据库中获取和存储时间值。

以下是一个示例实现,它重用/别名了time.Time,但不使用日期、月份和年份数据:

const MyTimeFormat = "15:04:05"

type MyTime time.Time

func NewMyTime(hour, min, sec int) MyTime {
	t := time.Date(0, time.January, 1, hour, min, sec, 0, time.UTC)
	return MyTime(t)
}

func (t *MyTime) Scan(value interface{}) error {
	switch v := value.(type) {
	case []byte:
		return t.UnmarshalText(string(v))
	case string:
		return t.UnmarshalText(v)
	case time.Time:
		*t = MyTime(v)
	case nil:
		*t = MyTime{}
	default:
		return fmt.Errorf("cannot sql.Scan() MyTime from: %#v", v)
	}
	return nil
}

func (t MyTime) Value() (driver.Value, error) {
	return driver.Value(time.Time(t).Format(MyTimeFormat)), nil
}

func (t *MyTime) UnmarshalText(value string) error {
	dd, err := time.Parse(MyTimeFormat, value)
	if err != nil {
		return err
	}
	*t = MyTime(dd)
	return nil
}

func (MyTime) GormDataType() string {
	return "TIME"
}

你可以像这样使用它:

type Building struct {
	ID        int    `json:"id,omitempty"`
	Name      string `gorm:"size:255" json:"name,omitempty"`
	Lon       string `gorm:"size:64" json:"lon,omitempty"`
	Lat       string `gorm:"size:64" json:"lat,omitempty"`
	StartTime MyTime `json:"start_time,omitempty"`
	EndTime   MyTime `json:"end_time,omitempty"`
}

b := Building{
	Name:      "test",
	StartTime: NewMyTime(10, 23, 59),
}

为了正确支持JSON,你需要为json.Marshaler/json.Unmarshaler添加实现,这留给读者作为练习。

英文:

While gorm does not support the TIME type directly, you can always create your own type that implements the sql.Scanner and driver.Valuer interfaces to be able to put in and take out time values from the database.

Here's an example implementation which reuses/aliases time.Time, but doesn't use the day, month, year data:

const MyTimeFormat = "15:04:05"

type MyTime time.Time

func NewMyTime(hour, min, sec int) MyTime {
	t := time.Date(0, time.January, 1, hour, min, sec, 0, time.UTC)
	return MyTime(t)
}

func (t *MyTime) Scan(value interface{}) error {
	switch v := value.(type) {
	case []byte:
		return t.UnmarshalText(string(v))
	case string:
		return t.UnmarshalText(v)
	case time.Time:
		*t = MyTime(v)
	case nil:
		*t = MyTime{}
	default:
		return fmt.Errorf("cannot sql.Scan() MyTime from: %#v", v)
	}
	return nil
}

func (t MyTime) Value() (driver.Value, error) {
	return driver.Value(time.Time(t).Format(MyTimeFormat)), nil
}

func (t *MyTime) UnmarshalText(value string) error {
	dd, err := time.Parse(MyTimeFormat, value)
	if err != nil {
		return err
	}
	*t = MyTime(dd)
	return nil
}

func (MyTime) GormDataType() string {
	return "TIME"
}

You can use it like:

type Building struct {
	ID        int    `json:"id,omitempty"`
	Name      string `gorm:"size:255" json:"name,omitempty"`
	Lon       string `gorm:"size:64" json:"lon,omitempty"`
	Lat       string `gorm:"size:64" json:"lat,omitempty"`
	StartTime MyTime `json:"start_time,omitempty"`
	EndTime   MyTime `json:"end_time,omitempty"`
}

b := Building{
	Name:      "test",
	StartTime: NewMyTime(10, 23, 59),
}

For proper JSON support you'll need to add implementations for json.Marshaler/json.Unmarshaler, which is left as an exercise for the reader 😉

答案2

得分: 0

如在“在使用GORM和Postgresql时如何在数据库中节省时间?”中提到:

目前,GORM不支持除了timestamp with time zone之外的任何日期/时间类型。

因此,您可能需要将时间解析为日期:

time.Parse("2006-01-02 3:04PM", "1970-01-01 9:00PM")
英文:

As mentioned in "How to save time in the database in Go when using GORM and Postgresql?"

> Currently, there's no support in GORM for any Date/Time types except timestamp with time zone.

So you might need to parse a time as a date:

time.Parse("2006-01-02 3:04PM", "1970-01-01 9:00PM")

答案3

得分: 0

我遇到了相同的错误。看起来数据库中的列类型与 Gorm 模型不匹配。

可能是数据库中的列类型是文本类型,你可能之前设置了这个类型,然后在 Gorm 模型中更改了列类型。

英文:

I am have come across the same error. It seems like there is a mismatch between type of the column in the database and the Gorm Model

Probably the type of the column in the database is text which you might have set earlier and then changed the column type in gorm model.

huangapple
  • 本文由 发表于 2017年2月4日 15:04:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/42037562.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定