亚洲/上海 or 中华人民共和国(PRC)的 pytz.timezone 和 「北京时间」有 6 分钟偏移。
原因有历史原因,可以搜索到!
所以在处理“北京时间”的时候,需要掌握一定的知识。
以下内容都默认输入的时间(字符串等)都是北京时间,而且不带时区后缀
- 使用 Python 的 datetime.datetime(<北京时间>).timestamp() 得到的是正确的时间戳(timestamp);除非你电脑的系统时区不是中国的。
也就是说,datetime.datetime 没有指定时区的话,得到的 datetime.datetime 实例使用的时区(默认时区)就是 Python 运行环境的时区(一般就是操作系统设定的时区)。
所以,如果你在中国使用电脑,电脑设定的时区是中国,你创建的 datetime.datetime 实例中的时间是北京时间,那么:
instance.timestamp() # instance: <datetime.datetime>
得到的就是正确的时间戳。 作为一名软件工程师,应当要考虑到自己写的代码不止在一处电脑运行;所以不能绝对保证 Python 的运行环境时区就是中国的(生产环境上,这一点应该有运维保证)。
那么,对于不含有指定时区的「日期时间」输入,但我们要将这个输入作为【北京时间】处理的时候,就应该多敲几个字符 ensure 得到的 datetime.datetime 实例上的时区信息是 UTC+8:00 的,怎么做到这一点?
看如下代码:
>>> import datetime as dt
>>> import pytz
>>> pytz.timezone('Asia/Shanghai').localize(
... dt.datetime(2020, 9, 25, 18, 12, 23)
... ).timestamp() # correct way
1601028743.0
>>>
>>> dt.datetime(2020, 9, 25, 18, 12, 23).replace(
... tzinfo=pytz.timezone('Asia/Shanghai')
... ).timestamp() # 00:06 offset
1601028383.0
这段代码直接 .timestamp() 取了时间戳
各位也可以去掉 .timestamp() 看出来
pytz.timezone(<时区>).localize(<datetime.datetime>)
和
datetime.datetime.replace(tzinfo=pytz.timezone(<时区>))
得到的 datetime.datetime 实例结果中,tzinfo 的不同(自己试一下)。
即,使用 .localize 的方式才是处理【北京时间】的正确方式!
- “ensure 得到的 datetime.datetime 实例上的时区信息是 UTC+8:00”
之所以这么做,是因为这个帖子,原本的问题是得到 Unix timestamp【时间戳】的问题;
在 Python 中,【过去日期时间】的时间戳使用借由 datetime.datetime 获得是很合理的方式!
获取时间戳的方式就是
instance.timestamp() # instance: <datetime.datetime>
但是这么获取时间戳的时候,python 需要知道这个 datetime.datetime 的 instance 是哪个时区的,才能计算时间戳;默认时区的方式我在 1. 中已经说了,如果没理解请回到 1. 点再看一下。
但是如果我们考虑默认时区不是 UTC+8:00 的话,那么从 datetime.datetime 实例计算时间戳就会有问题;所以我们可以通过 2. 中的两种方式(.replace
, .localize
) 来得到含有【中国时区】(tzinfo)的 datetime.datetime 实例,然后由这个实例计算时间戳就是正确的了。
而因为历史原因,所以 .replace
的解决方案会有 6 分钟的 offset,所以,实际上我们处理【北京时间】的正确方式应当是 .localize
的方式。
最后,即使不是求【时间戳】,我们可能需要处理一个【日期时间】字符串为 Python 的 datetime.datetime 实例,那么也应该使用 .localize
为其添加上 tzinfo 信息(UTC+8:00)
除了 pytz 还有其它库可以处理时区;这里不再做展开。
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…