当前位置: 首页 > 知识库问答 >
问题:

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

孙海
2023-06-18
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

共有2个答案

叶展
2023-06-18

这其实是两个问题。


首先你这里差 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。

吕永嘉
2023-06-18

维基百科是这么讲的:

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

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

 类似资料:
  • 本文向大家介绍为什么Java不支持<<相关面试题,主要包含被问及为什么Java不支持<<时的应答技巧和注意事项,需要的朋友参考一下 Java添加了运算符“ >>>”来执行逻辑右移,但是由于 逻辑和算术左移运算是相同的 ,因此Java中没有“ <<<”运算符。 来自Java的Shifts …

  • 我注意到一件奇怪的事情,显然Firefox说它支持HTTPS上的Brotli,但不支持HTTP?Brotli与gzip类似,但效率更高,为什么它会将其限制为HTTPS?在HTTPS选项卡上,我看到: 他被派去了。但在另一个网站上,我没有看到。为什么它不能做Brotli压缩HTTP?

  • 问题内容: 是当今的浏览器是否经过深思熟虑的设计决策或存在问题,这些问题将在以后的版本中得到解决? 问题答案: JavaScript不支持多线程,因为浏览器中的JavaScript解释器是单线程(AFAIK)。甚至谷歌浏览器也不允许单个网页的JavaScript同时运行,因为这会在现有网页中引起大量的并发问题。Chrome所做的全部工作就是将多个组件(不同的选项卡,插件等)分离到单独的进程中,但是

  • 在EpolDatagramChannelConfig类中,有4个方法如下所示: 这些是: SETLOOPBACKMODE已禁用 是否由于Netty中的问题而禁用了支持,或者EPoll根本不支持UDP多播? 谢谢

  • 问题内容: Java为什么不包括对无符号整数的支持? 在我看来,这是一个奇怪的遗漏,因为它们允许人们编写不太可能在意外大的输入上产生溢出的代码。 此外,使用无符号整数可以是一种自我证明的形式,因为它们指示无符号int打算保留的值永远不会为负。 最后,在某些情况下,无符号整数对于某些操作(例如除法)可能更有效。 包括这些的不利之处是什么? 问题答案: 在两行之间阅读时,我认为逻辑是这样的: 通常,J

  • 问题内容: 我已经多次看到,负填充的前景可能会帮助某些页面元素的CSS开发变得越来越好。但是,W3C CSS中没有负填充的规定。这背后的原因是什么?该属性是否有阻碍其使用的阻碍?感谢您的回答。 更新 例如,我看到的情况是,如果您使用的字体的垂直间距为20px,并且希望在字体底部应用虚线边框,例如出现超链接时。在这种情况下,您会发现样式太简陋,因为虚线边框会出现在指定单词下方20px。如果您使用负边