如何强制zoneinfo使用Python tzdata库,而不是系统tzdata,或者,为什么在不同平台上得到的UTC偏移量不同?

编程语言 2026-07-09

我遇到了一个问题,可能是我这边的用户错误、也可能是Python的 zoneinfo与 tzdata模块在不同平台上的行为不一致,或者IANA数据库在各个平台之间存在差异。

我发现,是否在同一个IANA数据库下,取决于所处的平台,zoneinfo库进行utcoffset计算的结果会不同,即使使用的IANA数据库相当相似。这些日期都在1970年之前,包括应与UTC有偏移的日期,以及基于LMT的日期。我的测试输出的完整结果如下。

那么我的核心问题是:这是怎么回事?我如何强制zoneinfo使用已安装(且在通过uv管理的虚拟环境中锁定版本)的Python tzdata库,而不是系统tzdata?

以下是我部分测试的结果、所使用的平台,以及已安装的tzdata库版本。

Ubuntu noble,tzdata 2026a-0ubuntu0.24.04。

Python 3.12.3 (main, Mar 23 2026, 19:04:32) [GCC 13.3.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 9.5.0 -- An enhanced Interactive Python. Type '?' for help.
Tip: You can use `files = !ls *.png`

In [1]: import zoneinfo

In [2]: from datetime import datetime

In [3]: zoneinfo.ZoneInfo("Europe/Amsterdam").utcoffset(datetime(1923, 12, 1, 13
      ⋮ , 43, 12)).total_seconds()
Out[3]: 1172.0

In [4]: zoneinfo.ZoneInfo("Europe/Amsterdam").utcoffset(datetime(1023, 12, 1, 13
      ⋮ , 43, 12)).total_seconds()
Out[4]: 1172.0

In [5]: zoneinfo.TZPATH
Out[5]: 
('/usr/share/zoneinfo',
 '/usr/lib/zoneinfo',
 '/usr/share/lib/zoneinfo',
 '/etc/zoneinfo')

MacOS Sequoia 15.7.2,zoneinfo版本2025c

Python 3.12.12 (main, Mar 23 2026, 19:04:32) [GCC 13.3.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 9.5.0 -- An enhanced Interactive Python. Type '?' for help.
Tip: You can use `files = !ls *.png`

In [13]: import zoneinfo

In [14]: from datetime import datetime

In [15]: zoneinfo.ZoneInfo("Europe/Amsterdam").utcoffset(datetime(1923,12,1,13,4
       ⋮ 3,12)).total_seconds()
Out[15]: 0.0

In [16]: zoneinfo.ZoneInfo("Europe/Amsterdam").utcoffset(datetime(1023,12,1,13,4
       ⋮ 3,12)).total_seconds()
Out[16]: 1050.0

In [17]: zoneinfo.TZPATH
Out[17]:
('/usr/share/zoneinfo',
 '/usr/lib/zoneinfo',
 '/usr/share/lib/zoneinfo',
 '/etc/zoneinfo')

raspbian bookworm,tzdata 2025b-0+deb12u2

Python 3.11.2 (main, Apr 28 2025, 14:11:48) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import zoneinfo
>>> from datetime import datetime
>>> zoneinfo.ZoneInfo("Europe/Amsterdam").utcoffset(datetime(1923, 12, 1,13,43,12)).total_seconds()
1172.0
>>> zoneinfo.ZoneInfo("Europe/Amsterdam").utcoffset(datetime(1023, 12, 1,13,43,12)).total_seconds()
1172.0
>>> zoneinfo.TZPATH
('/usr/share/zoneinfo', '/usr/lib/zoneinfo', '/usr/share/lib/zoneinfo', '/etc/zoneinfo')
>>

Windows 10,PowerShell,使用uv安装的Python,tzdata版本为2026b

Python 3.12.1 (tags/v3.12.1:2305ca5, Dec  7 2023, 22:03:25) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.                                     
>>> import zoneinfo
>>> import tzdata
>>> from datetime import datetime
>>> zoneinfo.ZoneInfo("Europe/Amsterdam").utcoffset(datetime(1923, 12, 1,13,43,12)).total_seconds()
0.0
>>> zoneinfo.ZoneInfo("Europe/Amsterdam").utcoffset(datetime(1023, 12, 1,13,43,12)).total_seconds()
1050.0
>>> zoneinfo.TZPATH
()
>>> tzdata.IANA_VERSION
'2026b'

所以这里的异常点是MacOS,其tzdata为 2025c,以及Windows使用uv安装的tzdata版本为2026b。相反,raspbian的 tzdata为 2025b,Ubuntu的 tzdata为 2026a,二者都给出相同的结果。

我浏览了 IANA tz邮件列表的公告,并没有发现这些版本之间对Europe/Amsterdam文件的变更提及。

到目前为止,我完全被搞糊涂了,也不知道为什么在这些版本之间zoneinfo文件没有(我能找到的)变更的情况下,在不同平台上会得到不同的结果。我可能误解了zoneinfo和 tzdata在不同平台上的工作方式。

(注意,我也尝试通过将datetime调用显式设为 “Etc/UTC” 来让时区感知到这一点,但问题仍然存在。)

对此的任何帮助都将不胜感激!

解决方案

据chatty的说法

即使tzdata文件没有变化,zoneinfo仍可能在不同的操作系统上产生不同的结果,因为每个平台可能使用不同的时区数据源(系统tzdata与 PyPI tzdata包),并且对于像公元1023年这样的极早日期,由于IANA数据库中的历史规则不完整或未定义,处理方式可能不同;再加上Python的 zoneinfo在不同操作系统上的回退行为,即使底层数据看起来未变,也会导致偏移不一致。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章