Golang中time.Time转换为Unix时间戳时出现额外小时数的问题

Golang中time.Time转换为Unix时间戳时出现额外小时数的问题 我遇到了一个问题。PostgreSQL数据库以“不带时区的时间戳”格式存储日期和时间。如果从数据库获取日期和时间并尝试将其转换为秒,它会额外增加4个小时。示例:

fmt.Println(menu.OpeningRecordAt, "|", time.Unix(menu.OpeningRecordAt.Unix(), 0))
// 2023-05-21 00:00:00 +0000 UTC | 2023-05-21 04:00:00 +0400 +04

有哪些方法可以修复这个问题,或者更正确地转换日期和时间秒数?

我尝试将PostgreSQL中的数据类型更改为带时区的时间戳,但转换仍然会额外增加小时数。


更多关于Golang中time.Time转换为Unix时间戳时出现额外小时数的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

这些是相同的时间戳。一个是UTC时间,另一个是本地时间(在你的例子中是+0400)。如果你将时间戳存储为UTC,那么加上4小时来获取本地时间是正确的。

更多关于Golang中time.Time转换为Unix时间戳时出现额外小时数的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


补充一下上面 @Dean_Davidson 所说的……在右边的那个加上 .UTC(),或者在左边的那个加上 .Local()

PS:如果可能的话,处理时间时请始终使用 UTC。

您遇到的问题与从 PostgreSQL 数据库检索数据时的时区转换有关。要正确处理此问题,您需要考虑与时间戳关联的时区信息并进行适当的转换。以下是几种准确修复或转换日期和时间的方法:

  1. 指定时区:确保在连接到 PostgreSQL 数据库时设置适当的时区。您可以在连接字符串中指定时区,或在连接后使用 SET TIME ZONE 命令。这样可以确保检索到的时间戳根据所需的时区进行调整。
  2. 使用时区函数:PostgreSQL 提供了各种与时区相关的函数,允许您基于特定时区操作和转换时间戳。可以使用 AT TIME ZONEtimezone() 等函数将时间戳转换为特定时区或根据特定偏移量进行调整。
  3. 在 Go 中处理时区转换:您可以选择不依赖 PostgreSQL 处理时区转换,而是按原样检索时间戳并在 Go 中执行转换。您可以使用 time.Time 类型的 In() 方法将时间转换为特定时区。示例如下:
// 假设 menu.OpeningRecordAt 是 time.Time 类型
loc, _ := time.LoadLocation("YourDesiredTimeZone")
convertedTime := menu.OpeningRecordAt.In(loc)

"YourDesiredTimeZone" 替换为您希望将时间戳转换到的时区。这种方法让您可以在 Go 代码中更灵活地控制时区转换。

  1. 规范化时区处理:如果您的应用程序涉及多个时区,建立一种一致的时区处理方法至关重要。在将时间戳存储到数据库和从数据库检索时,将所有时间戳规范化为单一时区(例如 UTC)。然后根据用户偏好或要求显式执行任何必要的时区转换。

遵循这些方法,您可以确保正确执行日期和时间转换,从而解决 PostgreSQL 数据库与您的应用程序之间的时区差异问题。

问题在于Go的time.Time类型包含时区信息,而PostgreSQL的"不带时区的时间戳"在解析时会默认使用UTC时区。当您调用Unix()方法时,返回的是UTC时间的Unix时间戳,但用time.Unix()重新构造时间时,会使用系统的本地时区。

以下是几种解决方案:

方案1:使用UTC时间统一处理

// 将时间转换为UTC时区后再获取Unix时间戳
unixTime := menu.OpeningRecordAt.UTC().Unix()
fmt.Println(unixTime)

// 重新构造时也使用UTC
reconstructed := time.Unix(unixTime, 0).UTC()
fmt.Println(reconstructed)

方案2:在数据库查询时处理时区

// 在SQL查询中使用AT TIME ZONE
query := `SELECT opening_record_at AT TIME ZONE 'UTC' FROM menus`
// 或者使用您本地的时区
query := `SELECT opening_record_at AT TIME ZONE 'Asia/Tbilisi' FROM menus`

方案3:使用time.Time的In方法指定时区

// 明确指定时区
location, _ := time.LoadLocation("Asia/Tbilisi") // 根据您的时区调整
localTime := menu.OpeningRecordAt.In(location)
fmt.Println(localTime.Unix())

// 或者始终使用UTC
utcTime := menu.OpeningRecordAt.In(time.UTC)
fmt.Println(utcTime.Unix())

方案4:检查数据库连接时区设置

// 在数据库连接字符串中指定时区
connStr := "host=localhost user=postgres dbname=test sslmode=disable TimeZone=Asia/Tbilisi"

关键点:

  1. PostgreSQL的"timestamp without time zone"不存储时区信息,Go驱动程序会将其解析为UTC时间
  2. Unix()方法返回的是UTC时间的秒数
  3. time.Unix()使用本地时区构造时间对象

建议在应用程序中统一使用UTC时间进行处理,只在显示时转换为本地时区。这样可以避免时区转换带来的混乱。

回到顶部