使用 GORM 和 Postgresql 时如何在 Go 中节省数据库时间?

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

我目前正在解析时间字符串并将其保存到数据库 (Postgresql):

event.Time, _ := time.Parse("3:04 PM", "9:00 PM")
// value of event.Time now is: 0000-01-01 21:00:00 +0000 UTC
db.Create(&event)

它给我这个错误:pq: R:"DateTimeParseError" S:"ERROR" C:"22008" M:"date/time field value out of range: \"0000-01-01T21:00:00Z\"" F:"datetime.c" L:"3540"

event.Time⁠⁠⁠⁠ 的类型是 time.Time.

我还尝试将 event.Time 的类型设置为字符串并在 postgresql 中使用时间数据类型:

type Event struct {
  Time string `gorm:"type:time
}

但现在我在数据库中获取记录时遇到错误:

sql: Scan error on column index 4: unsupported driver -> Scan pair: time.Time -> *string

进一步调查了这个问题。目前,GORM 不支持任何 Date/Time 类型,除了 timestamp with time zone

这部分代码来自dialect_postgres.go:

case reflect.Struct:
   if _, ok := dataValue.Interface().(time.Time); ok {
      sqlType = "timestamp with time zone"
}

所以基本上我看到两个选项供您选择:

在 DB 中使用 varchar(10),在 Go 中使用 string,只需将其保存为“9:00 PM”(其中 10 是适合您的数字)

或者在 DB 中使用 timestamp with time zone,在 Go 中使用 time.Time,并将日期部分格式化为固定日期 01/01/1970,例如:

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

在这种情况下,您必须在演示文稿中省略日期部分,但如果您计划 select 按日期范围,那可能更适合您。

更新 SQL 中的 DATETIME 字段时,Go 字符串必须采用以下格式:time.Now().Format(time.RFC3339).

从 Postgres 的角度来看,错误源于没有年份 0000。如果您没有日期,您可以将 1 年添加到转换后的时间戳,给出 '0001-01-01T21:00:00+ 00' 这是一个有效的 Postgres 时间戳。

select '0000-01-01T21:00:00+00'::timestamptz at time zone 'UTC' 
ERROR:  date/time field value out of range: "0000-01-01T21:00:00+00"

给了他同样的错误。正如 0001-01-01 前 1 天的演示一样:

select '0001-01-01T21:00:00+00'::timestamptz at time zone 'UTC' - interval '1 day' "day_before_1/1/1";
--day_before_1/1/1
--0001-12-31 21:00:00 BC

您可以使用 sql 标签

通过 Gorm 设置任意特定于数据库的类型
type Event struct {
  Time time.Time `sql:"type:timestamp without time zone"`
}