import pytz
from datetime import datetime
print(datetime.now().replace(tzinfo=pytz.timezone('Asia/Shanghai')))
输出
2023-06-17 13:03:10.299279+08:06
pytz 只支持 上海时间,不支持 北京时间
但是上海时间有一个很恶心的地方,会比北京时间多 6 分钟
同样的问题,在我使用一些 linux 发行版(带GUI)的时候,也遇到过这样的问题,只能设置上海时间,没有北京时间可以选
why?是有什么国际法规定吗?
from zoneinfo import ZoneInfo
from datetime import datetime
import pytz
print(datetime.now().replace(tzinfo=pytz.timezone('Asia/Shanghai')))
tz = ZoneInfo('Asia/Shanghai')
print(datetime.now(tz))
不过 python3.9 内置的 zoneinfo,但是不会出现多 6 分钟的问题
输出如下:
2023-06-17 13:36:54.594807+08:06
2023-06-17 13:36:54.605920+08:00
这其实是两个问题。
首先你这里差 6 分钟是因为 pytz 内部默认采用的是一种叫 Local Mean Time(LMT,当地平均时间)的时区。这种时区是纯粹按照地理经度来划分的,大概每个经度差 4 分钟左右……
当我们提到 “Asia/Shanghai” 这个时区名称的时候,其实是有三种时区的(到目前为止,以后说不定还会增加):
你直接这么 print 出来,是按 LMT 的方式格式化输出的。所以你得到了一个差了 6 分钟的结果。
而我们通常所说 “Asia/Shanghai”,在绝大部分情况下指的是标准时间而非平均时间。
在 pytz 里你要想以标准时间输出的话,需要手动
normalize
或localize
。具体写法就不给了,你自己就能查到。至于 pytz 默认为啥要采用 LMT 存储,这个我们就不得而知了。但项目已经开源这么久了,这种上古级别的 feature 想要改是很难的了。
其次是关于所谓“北京时间”的问题。
如果你仅仅是想要一个 UTC+8,前面我已经解释了原因和做法。
而如果你问的是为什么罕见有 “Asia/Beijing” 或 “Asia/Peking” 这种时区名称。上面 @非马梦衢 已经解释了部分原因。其中提到一点:
那么到底是谁“参考”、又是谁“选择”的呢?
其实就是计算机中时区数据库,通常来自于 Time Zone Database(简称 tzdb)这一开源项目。虽然它现在名义上已被 ICANN 接管,是一项“半国际标准”。但实质上从开始到现在,它始终都是 Paul Eggert (保罗·埃格特)一个人维护的,所以几乎可以看作是一个私人项目。这个人是一个很“固执”的老头,他自有一套判断标准来决定讲哪些地区或城市纳入到该数据库中。
实际上世界上很多其他国家和地区的人,也都吐槽过自己所在国家或地区的代表性城市也没有出现在 tzdb 里,对吐槽感兴趣的话可以看 https://www.36kr.com/p/1473253583024389 这篇报道。
也有一些软件出于种种原因,没有完全使用 tzdb,而是自己另行维护了一套时区数据库。它们就有可能是支持 Asia/Beijing 或 Asia/Peking 这种写法的。比较典型的比如 Windows。
所以回到你的问题里,“为什么很多东西不支持北京时间”,其实不是不支持“北京标准时间”、而是仅仅不支持 “Asia/Beijing” 这个时区名称而已。为啥不支持 —— 因为它们直接用的 tzdb,里面确实就是没有 Asia/Beijing。