如何比较仅时区表示不同的两个time.Time时间戳?Postgres testify测试场景
问题本质
assert.Equal判断time.Time类型等值时,会逐字段比对结构体的所有成员,包括内部绑定的时区对象指针:
- 手动构造的期望值,时区直接绑定Go标准库全局唯一的
time.UTC单例对象,打印显示为2020-10-31 00:00:00 +0000 UTC - PG驱动查询返回的时间值,内部绑定的是驱动动态生成的零偏移时区实例,不是全局单例,打印显示为
2020-10-31 00:00:00 +0000 +0000 - 两个值代表的绝对时间完全一致,只是时区元数据的指针不同,才触发断言失败,并非数据库存储的时间值不对。
可行的解决方法
方法1:标准化时区后直接断言(改动最小,推荐)
在断言前把两个时间都强制转换为绑定全局UTC单例的实例,消除时区元数据的差异,不需要修改原有日期创建逻辑:
assert.Equal(t, want.Date.UTC(), got.Date.UTC(), )
这种方式是严格等值校验,不会像浮点近似断言那样放过真实的时间差问题,只要两个时间对应的绝对时刻一致,转换完成后两个实例的所有字段就会完全匹配,不需要关心原来的时区元数据是什么样的。
方法2:逐字段校验核心时间维度
如果测试场景本来就只需要校验年月日时分秒这些业务字段,不需要关注时区相关的元数据,直接拆分字段做断言即可:
assert.Equal(t, want.Date.Year(), got.Date.Year()) assert.Equal(t, want.Date.Month(), got.Date.Month()) assert.Equal(t, want.Date.Day(), got.Date.Day()) assert.Equal(t, want.Date.Hour(), got.Date.Hour()) assert.Equal(t, want.Date.Minute(), got.Date.Minute()) assert.Equal(t, want.Date.Second(), got.Date.Second())
这种方式适配PG存储timestamp without time zone类型的场景,完全不涉及时区的比较逻辑。
方法3:转换为时间戳做比较
直接绕开time.Time的结构体比对逻辑,取两个时间的毫秒/微秒级时间戳做等值校验:
// 按毫秒精度校验,适配大部分业务场景 assert.Equal(t, want.Date.UnixMilli(), got.Date.UnixMilli(), )
精度需求更高的场景可以替换为UnixMicro()方法,比对过程完全不会受到内部时区对象差异的影响。
关于「创建无时区time.Time」的说明
Go的time.Time结构本身不存在“无绑定时区”的状态,哪怕PG返回的没有命名的+0000时区值,本质也是绑定了一个零偏移的时区实例,不存在传nil创建纯时间值的用法。不需要刻意修改日期创建逻辑去模拟“无时区”的效果,只要在断言环节做时区标准化处理,就能解决比较不通过的问题。
内容的提问来源于stack exchange,提问作者user9503053
相关产品推荐
相关产品推荐

