【问题标题】:Saving time.Time in golang to postgres timestamp with time zone field节省时间。时间在 golang 到 postgres 时间戳与时区字段
【发布时间】:2020-02-28 01:11:12
【问题描述】:

我正在尝试在 golang 中测试我的数据库(即 Postgres)模型。问题是当我从数据库中检索时,一个字段值与 time.Time 类型不匹配。这是代码:

a := myStruct{aTime: time.Now().UTC(), ...}
res, err := db.Exec("INSERT INTO my_table VALUES ($1, $2, ...) RETURNING id", a.aTime, ...)
...
// some logic for setting id in struct a
...
row := db.QueryRow("SELECT * FROM my_table WHERE id = $1", a.id)
var test *myStruct
row.Scan(test)
reflect.DeepEqual(a, test) // returns False
fmt.Printf("%v\n%v", a, test)
// {2020-02-25 12:37:16.906605805 +0000 UTC ...}
// {2020-02-25 12:37:16.906606 +0000 UTC ...}

数据库中的时间字段类型为timestamp with time zone

我也尝试了以下方法:

a.aTime.Equal(test.aTime) // returns false
a.aTime = a.aTime.Round(time.Second)
test.aTime = test.aTime.Round(time.Second)
a.aTime.Equal(test.aTime) // returns true

但仍然 reflect.DeepEqual 返回 false。问题是时间字段,因为当我执行以下操作时,reflect.DeepEqual 变为 true

a.aTime = test.aTime

有谁知道如何解决这个问题?

【问题讨论】:

  • 不要使用reflect.DeepEqual比较时间,使用time.Equal()。如果您想比较两次的 TZ,那么您可以提取带有 time.Zone()time.Location() 的 TZ
  • 谢谢,@colminator reflect.DeepEqual 让比较结构变得如此简单。您有什么简单的解决方案来比较包含时间字段的结构吗?我不想使用带有 4 行条件的 if。
  • reflect 只有在编写任何人都会使用的通用框架时才应该使用。 reflect 也很慢。如果您有一个具有有限类型定义的具体应用程序,则确实没有必要使用它。如果你有一个复杂的结构并且想要避免样板比较代码,那么创建一个 Equal 方法一次 - 并避免在其他地方使用样板。
  • reflect 会给你错误的否定,任何时区不同,或者任何时候单调时间不同(几乎每次你用time.Now() 或类似的初始化时间)。 尽可能避免反思。示例:play.golang.org/p/DaPKdY1C-ty

标签: postgresql go


【解决方案1】:

这些时间不相等:

// {2020-02-25 12:37:16.906605805 +0000 UTC ...}
// {2020-02-25 12:37:16.906606 +0000 UTC ...}

DB 值具有(四舍五入)微秒精度 - go 的时间具有纳秒精度。

我建议您在将它们添加到数据库之前将您的时间四舍五入到您的数据库和您的需求支持的精度水平,例如

a.Atime = a.aTime.Round(time.Microsecond) // round to nearest micro (per Markus comment)

res, err := db.Exec("INSERT INTO my_table VALUES ($1, $2, ...) RETURNING id", a.aTime, ...)

还要比较时间相等性,使用time.Equal()

Equal 报告 t 和 u 是否表示同一时刻。二 即使它们在不同的位置,时间也可以相等。为了 例如,6:00 +0200 和 4:00 UTC 是相等的。请参阅有关文档 将 == 与 Time 值一起使用的陷阱的 Time 类型;大多数代码 应该使用 Equal 代替。

【讨论】:

  • PostgreSQL 仅以微秒精度存储。另一种选择是将 a.aTime.UnixNano() 存储为整数字段...但是您会丢失 TZ 信息并需要将其存储在其他地方,另外,您需要进行所有的修改。
猜你喜欢
  • 2018-11-26
  • 1970-01-01
  • 2017-08-08
  • 2021-12-31
  • 1970-01-01
  • 2015-03-03
  • 1970-01-01
  • 2020-04-07
  • 2013-01-14
相关资源
最近更新 更多