在Postgres中,我存储用户提供给我的数据:
Column | Type | Collation | Nullable | Default
------------+--------------------------+-----------+----------+---------
id | uuid | | not null |
value | numeric | | |
date | timestamp with time zone | | |
现在,我提出了保持生成数据的原始时区的要求。 timestamp with timezone
已归一化为数据库的时区,并且原始时区丢失了,因此在将其退还给用户之前,我必须从归一化的时区手动还原date
。
大多数解决方案建议在表中增加一列,并将原始时区信息与时间戳一起存储:
Column | Type | Collation | Nullable | Default
------------+--------------------------+-----------+----------+---------
id | uuid | | not null |
value | numeric | | |
date | timestamp with time zone | | |
tz | text | | |
假设我正在使用Go,应该从time.Time
中提取哪些信息以存储在tz
中,以进行最精确和无缝的恢复?
date.Location().String()
似乎不正确,因为它可能返回相对的值Local
。
我应该如何将信息从tz
恢复到time.Time
?
time.LoadLocation(tz)
的结果是否足够好?
答案 0 :(得分:2)
保存后,我将使用Time.Zone()
获取区域名称和偏移量:
func (t Time) Zone() (name string, offset int)
然后,当从数据库中查询这样的时间戳时,可以使用time.Location
来构建time.FixedZone()
:
func FixedZone(name string, offset int) *Location
然后使用Time.In()
切换到此位置。
警告!:这将为您在同一时区中显示“似乎”的时间戳,但是如果您需要对其进行操作(例如为其添加天数),则结果可能不一样。这样做的原因是因为time.FixedZone()
返回的时区具有固定的偏移量,例如对于daylight savings一无所知,而您保存的原始时间戳可能有一个time.Location
了解这些事情。
这是这种偏差的一个例子。 3月有一个夏令时,因此我们将使用指向3月1日的时间戳记,并为其添加1个月,这将导致时间戳记晚于夏令时。
cet, err := time.LoadLocation("CET")
if err != nil {
panic(err)
}
t11 := time.Date(2019, time.March, 1, 12, 0, 0, 0, cet)
t12 := t11.AddDate(0, 1, 0)
fmt.Println(t11, t12)
name, offset := t11.Zone()
cet2 := time.FixedZone(name, offset)
t21 := t11.UTC().In(cet2)
t22 := t21.AddDate(0, 1, 0)
fmt.Println(t21, t22)
now := time.Date(2019, time.April, 2, 0, 0, 0, 0, time.UTC)
fmt.Println("Time since t11:", now.Sub(t11))
fmt.Println("Time since t21:", now.Sub(t21))
fmt.Println("Time since t12:", now.Sub(t12))
fmt.Println("Time since t22:", now.Sub(t22))
这将输出(在Go Playground上尝试):
2019-03-01 12:00:00 +0100 CET 2019-04-01 12:00:00 +0200 CEST
2019-03-01 12:00:00 +0100 CET 2019-04-01 12:00:00 +0100 CET
Time since t11: 757h0m0s
Time since t21: 757h0m0s
Time since t12: 14h0m0s
Time since t22: 13h0m0s
如您所见,添加1个月后的输出时间相同,但是区域偏移不同,因此它们指定了不同的时间瞬间(这可以通过显示任意时间的时差来证明。 )。原始文件有2小时的偏移量,因为它知道我们跳过的1个月中发生的夏时制,而“还原的”时间戳记的区域对此一无所知,因此结果具有相同的1个小时的偏移量。在添加后的时间戳中,甚至区域名称在现实生活中也会发生变化:从CET
到CEST
,再一次,恢复的时间戳所在的区域也不知道这一点。
答案 1 :(得分:0)
更浪费且仍然容易出错,但仍然有效的解决方案是将原始时间戳记也以2019-05-2T17:24:37+01:00
之类的ISO 8601格式存储在单独的列datetext
中:
Column | Type | Collation | Nullable | Default
------------+--------------------------+-----------+----------+---------
id | uuid | | not null |
value | numeric | | |
date | timestamp with time zone | | |
datetext | text | | |
然后使用date
查询本机时间戳列的强度,并返回给用户datetext
,这是最初发送的确切值。