PostgreSql时间类型timestamp的一次错误排查

问题:

币商需求中,qa发现在页面中的时间,都比实际的时间延后了8小时:

解决方式:

修改数据库时间字段的默认值,由now() 改为 timezone('UTC'::text, now())

image.png

问题得到解决:

image.png

原理探究:

参照资料:http://www.postgres.cn/docs/9.4/datatype-datetime.html

image.png

资料中的两句话,可以解释最初的问题:

“timestamp类型等于timestamp without time zone 类型”

“如果一个文本已被确定是timestamp without time zone,PostgreSQL 将悄悄忽略任何文本中指出的时区。”

分析:

now()会根据当前会话中使用的时区,返回为带有时区的时间字符串:

image.png

image.png

应用服务与数据库的会话,应该是使用了北京时区,而"悄悄忽略任何文本中指出的时区"后,将北京时间作为无时区时间,存入了时间字段。

结合目前在用的orm框架gitlab.p1staff.com/common/postgres/pgv6试验:

查询时:timestamp字段,返回的内容为不带时区时间字符串,orm会作为UTC时间来转换为time.Time类型

gitlab.p1staff.com/common/[email protected]+incompatible/types/time.go:23

image.png

到此,时间字段已经达成了 在应用中,将北京时间作为UTC时间了。

改为 timezone('UTC'::text, now())后,默认时间不受会话中使用时区影响,返回不带时区的UTC时间字符串。让时间字段正确存储UTC时间。

image.png

扩展探究:

对timestamp字段进行范围查询时,会不会有时区问题?确保字段存的是UTC时间,就不会。orm拼接time.Time类型数据时,会处理成UTC时间字符串。

gitlab.p1staff.com/common/[email protected]+incompatible/types/time.go:47

image.png

image.png

虽然拼的字符串有时区,但timestamp字段会"悄悄忽略任何文本中指出的时区"

你可能感兴趣的:(PostgreSql时间类型timestamp的一次错误排查)