为什么 pytz 不支持 北京时间(为什么很多东西不支持北京时间)?

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
阅读 3.5k
2 个回答

这其实是两个问题。


首先你这里差 6 分钟是因为 pytz 内部默认采用的是一种叫 Local Mean Time(LMT,当地平均时间)的时区。这种时区是纯粹按照地理经度来划分的,大概每个经度差 4 分钟左右……

当我们提到 “Asia/Shanghai” 这个时区名称的时候,其实是有三种时区的(到目前为止,以后说不定还会增加):

  • 当地标准时间,即 UTC+08:00。同时也是中国标准时间。
  • 当地平均时间,即 LMT+08:06。
  • 中国夏令时间(曾在 1986~1991 年短暂实行,现已废止),即 UTS+09:00。

你直接这么 print 出来,是按 LMT 的方式格式化输出的。所以你得到了一个差了 6 分钟的结果。

而我们通常所说 “Asia/Shanghai”,在绝大部分情况下指的是标准时间而非平均时间。

在 pytz 里你要想以标准时间输出的话,需要手动 normalizelocalize。具体写法就不给了,你自己就能查到。

至于 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。

维基百科是这么讲的:

IANA time zone database

The territory of the People's Republic of China is covered in the IANA time zone database by the following zones. "Asia/Shanghai" is used instead of "Asia/Beijing" because Shanghai is the most populous location in the zone.

维基百科也讲述了上海时间的由来历史, 仅供参考, Time_in_China#History

还有一个参考,是在某个github上看到一段文字,摘录部分,具体可参考链接: Timezone list does not contain Beijing

意思是说在现有的国际上,时钟数据库选择了以上海时间作为中国的标准时间来用的,是参考于当地时区内人口最多的地方,如果北京和上海人口相当,那选择最为著名的地方。

Here are the general guidelines used for choosing timezone names, in decreasing order of importance:

Use the most populous among locations in a region, e.g., prefer Asia/Shanghai to Asia/Beijing. Among locations with similar populations, pick the best-known location, e.g., prefer Europe/Rome to Europe/Milan.

这份维基百科的time zone数据库罗列了世界所有的时区: List_of_tz_database_time_zones

总之,在国际上来看,上海比北京知名度更高,所以他们的设计就是以上海为准。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏