如何准确比较两个时间实例?Go语言time.After()判断异常的时区问题排查
问题重现
你遇到的情况是:从数据库拿到时间实例have,用当前时间now()调用After()方法,直观上now更晚但返回false。具体时间如下:
have => 2022-01-09 09:09:59 +0000 +0000
now => 2022-01-09 11:57:08.990265878 +0300 +0300 m=+4.977355713
代码逻辑:
if now.After(have) { // ... 预期执行这里,但实际没执行 }
排查时发现have的Unix时间戳比now大,这就是After()返回false的直接原因。
核心原因:时区差异
Go语言的time.Time类型是带时区信息的,而Unix()方法返回的是从1970-01-01 00:00:00 UTC开始计算的秒数——本质上是把时间转换为UTC后的绝对时间戳。
我们来换算一下两个时间的绝对时间:
have是UTC+0的09:09:59,对应UTC时间就是09:09:59now是UTC+3的11:57:08,转换为UTC时间就是08:57:08(11:57减去3小时)
显然,UTC时间09:09比08:57要晚,所以have的Unix时间戳更大,now.After(have)自然返回false——这和你直观上看本地时间的感受相反,因为你忽略了两个时间的时区偏移。
解决办法
要正确比较两个时间,需要确保它们处于同一个时区。你已经找到的方法是把have转换到本地时区(和now一致):
loc, _ := time.LoadLocation("Local") have = have.In(loc)
转换后have变为2022-01-09 12:09:59 +0300 +0300,此时它的本地时间比now的11:57晚,now.After(have)就会返回符合预期的结果。
另外,也可以把两个时间都转换为UTC来比较,这样更通用(比如跨时区场景):
if now.UTC().After(have.UTC()) { // ... }
总结
在Go中比较时间时,一定要注意时间实例的时区信息,不要只看表面的本地时间数值。统一时区后再进行比较,才能得到正确的结果。
内容的提问来源于stack exchange,提问作者Amid

