时区与Unix时间戳

本文最后更新于:August 28, 2021 pm

今天在和 Rorical 做 Pixivel 新后端的时候,在获取图片的时间戳上出了点小差错。

太长不看

Python 的 datetime 库在接受输入时如果未指定时区,将会默认时区为本地时区。这可能会导致跨时区部署服务器集群时,时间戳出现不连贯。
例如如下代码:

1
2
3
4
from datetime import datetime
date_and_time = "2020-01-05 12:31:36"
formatted_date = datetime.strptime(date_and_time, %Y-%m-%d %H:%M:%S)
print(formatted_date.timestamp())

此代码会自动补全未给定的时区:

1
2
In America/New_York: 2020-01-05 12:31:36 GMT-5
In Asia/Shanghai: 2020-01-05 12:31:36 GMT+8

并转换为 UTC 时间:

1
2
1. 2020-01-05 17:31:36 GMT
2. 2020-01-05 04:31:36 GMT

并最终导致输出的时间戳不一致:

1
2
1. 1609867896
2. 1609821096

请一定在使用本库时再三检查是否提供了时区/部署环境与开发环境或者多个服务器集群之间时区是否一致,否则可能会导致时间戳异步。

全过程

“小问题”:

Rorical, [29.07.21 18:23]
我草这问题太诡异了

Rorical, [29.07.21 18:24]
同一个时间生成的时间戳不一样

Matrew File, [29.07.21 18:25]

Matrew File, [29.07.21 18:25]
wtf

Rorical, [29.07.21 18:28]
这个东西干扰到我的图片获取了

Rorical, [29.07.21 18:28]
想不通

Rorical, [29.07.21 18:31]
这是什么鬼问题

Matrew File, [29.07.21 18:31]
dunno

Matrew File, [29.07.21 18:31]
不应该啊

Matrew File, [29.07.21 18:31]
你这个应该就是个简单地Unix时间戳

Matrew File, [29.07.21 18:32]
又没有闰秒问题

Rorical, [29.07.21 18:36]
我这辈子遇到的最诡异问题

问题截图

经过简单蒙B之后,两人开始正常的问题分析过程:分析输出:

Matrew File, [29.07.21 18:37]
21096

Matrew File, [29.07.21 18:37]
67896

Matrew File, [29.07.21 18:37]
46800s

Matrew File, [29.07.21 18:38]
13个小时

问题似乎有了点头绪,但还是弯弯绕绕:

Matrew File, [29.07.21 18:38]
我猜是某种闰时制问题

Matrew File, [29.07.21 18:38]
或者是时区问题

Rorical, [29.07.21 18:38]
时区会影响时间戳吗

Matrew File, [29.07.21 18:38]
有可能

Matrew File, [29.07.21 18:38]
看这个差距

Matrew File, [29.07.21 18:39]
只有时区有可能

Matrew File, [29.07.21 18:39]
因为GMT制度里没有闰时一说

Matrew File, [29.07.21 18:39]
但也没有13时区啊……

Matrew File, [29.07.21 18:39]
我指的是

Matrew File, [29.07.21 18:40]
有可能一个实现把你给的时间认为是UTC

Matrew File, [29.07.21 18:40]
另外一个实现认为是系统时区

Rorical, [29.07.21 18:40]
这个确实有可能

Matrew File, [29.07.21 18:40]
但时间戳的计算基准是UTC 1970-01-01 00:00:00

Matrew File, [29.07.21 18:41]
问题是也没有13时区……

在又一次短暂蒙B之后,一点都不聪明的elf突然想到了事情的头绪:

Matrew File, [29.07.21 18:43]
一个是本地一个是服务器?

Matrew File, [29.07.21 18:43]
那确实有可能

Rorical, [29.07.21 18:43]

Matrew File, [29.07.21 18:43]
GMT+8 GMT-5

Matrew File, [29.07.21 18:43]
相差13小时

Matrew File, [29.07.21 18:44]
服务器上 cat /etc/timezone

Matrew File, [29.07.21 18:44]
我看下

Result

Matrew File, [29.07.21 18:45]

Matrew File, [29.07.21 18:45]
那解决了

Matrew File, [29.07.21 18:45]
纽约是GMT-4

附:纽约其实应该是GMT-5,我查询时正值美国夏令时,查询结果调前了一个时区,但服务器上没有,所以下文“加上东西十二区”其实并不用计算,GMT+8 - GMT-5 = 13

Matrew File, [29.07.21 18:45]
北京是GMT+8

Matrew File, [29.07.21 18:46]
加上个东西十二区

Matrew File, [29.07.21 18:46]
正好13个小时

Matrew File, [29.07.21 18:46]
两边应该都认为是当地时区

Matrew File, [29.07.21 18:46]
然后一算出问题了

Matrew File, [29.07.21 18:47]
[In reply to Rorical]
结果是地理没学好的问题

扩展阅读: