Python: strftime() 在Windows中UTC偏移不按预期工作

16 投票
5 回答
19494 浏览
提问于 2025-04-18 16:25

每次我使用:

time.strftime("%z")

我得到:

Eastern Daylight Time

不过,我想要的UTC时区偏移量格式是+HHMM或-HHMM。我甚至尝试过:

time.strftime("%Z")

但结果还是:

Eastern Daylight Time

我看过好几个关于strftime()的帖子,%z似乎总是能返回正确的+HHMM或-HHMM格式的UTC偏移量。请问我该如何让strftime()在Python 3.3中输出+HHMM或-HHMM格式呢?

补充:我在使用Windows 7。

5 个回答

0

我来这里是因为我需要一个解决方案,想要输出完整的日期和时间,包括时区,而且格式要符合RFC3339标准,具体可以查看这个链接 https://datatracker.ietf.org/doc/html/rfc3339 (是不是有点挑剔呢?) :)

看起来,strftime这个函数输出的内容并不符合这个特定的标准,所以最后我使用了:

from datetime import datetime, timezone
print(datetime.now(timezone.utc).astimezone().isoformat())

这个代码输出了以下内容:

2024-03-06T10:43:00.348657+00:00

我知道这并不是对问题的直接回答,但我觉得把它放在这里挺合适的,以防有人也像我一样走进这个迷宫 :)

0

这个问题在最新的Windows版本,也就是Win 10版本1703(创作者更新)中依然存在,大家应该早有耳闻。不过,时间总是向前走,现在有一个很棒的日期和时间库,叫做pendulum,它可以解决这个问题。这个库的主要作者是Sébatien Eustace,他向我展示过这个库的功能。

>>> pendulum.now().strftime('%z')
'-0400'

pendulum默认使用UTC/GMT时间,除非你特别说明其他时间。它还会把时区信息和日期时间对象一起保存。除此之外,还有很多其他的功能,下面列出了一些:

>>> pendulum.now(tz='Europe/Paris').strftime('%z')
'+0200'
>>> pendulum.create(year=2016, month=11, day=5, hour=16, minute=23, tz='America/Winnipeg').strftime('%z')
'-0500'
>>> pendulum.now(tz='America/Winnipeg').strftime('%z')
'-0500'
4

使用 time.timezone 可以获取时间偏移量,单位是秒。

然后可以用下面的方式格式化:

("-" if time.timezone > 0 else "+") + time.strftime("%H:%M", time.gmtime(abs(time.timezone)))

这样就能把它转换成 +/-HH:MM 的格式。

顺便问一下,这不是应该算是个bug吗?根据 strftime文档

我还以为 这个 StackOverflow 的回答能帮你把时区偏移字符串转换成 HH:MM 格式。不过因为 "%z" 没有按预期工作,我觉得这个问题就没什么意义了。

注意:time.timezone 不受夏令时的影响。

8

在2.x版本中,如果你查看time.strftime的文档,你会发现根本没有提到%z。这意味着它不一定存在,更别提在不同平台上的一致性了。实际上,正如脚注1所暗示的,这个功能是交给C语言的strftime函数来处理的。而在3.x版本中,他们确实提到了%z,不过解释它不按你预期工作的脚注并不容易找到;这就是一个未解决的bug

然而,在2.6及以上版本(包括所有3.x版本)中,datetime.strftime是可以保证支持%z的,表示“以+HHMM或-HHMM的形式表示的UTC偏移(如果对象是简单的,则为空字符串)”。所以,这里有一个简单的解决办法:用datetime代替time。具体怎么改要看你想做什么——如果你使用Python-dateutiltz,那么datetime.now(tz.tzlocal()).strftime('%z')就是获取本地时区格式化为GMT偏移的方式,但如果你想格式化一个完整的时间,细节会稍有不同。

如果你查看源代码,time.strftime基本上只是检查格式字符串中是否有适合该平台的标识符,然后调用本地的strftime函数,而datetime.strftime则对不同的标识符有很多特殊处理,包括%z;特别是,它会在传递给strftime之前,将%z替换为格式化后的utcoffset。自从2.7以来,这段代码经历了几次变化,甚至有一次彻底重组,但在3.5之前的版本中,这种差异基本上还是存在的。

7

要找到合适的解决方案,请查看 abarnert 的回答


你可以使用 time.altzone,它会返回一个负的时间偏移量(以秒为单位)。比如说,我现在在中欧夏令时(CEST,UTC+2),所以我得到的是:

>>> time.altzone
-7200

如果你想把它放成你想要的格式,可以这样做:

>>> '{}{:0>2}{:0>2}'.format('-' if time.altzone > 0 else '+', abs(time.altzone) // 3600, abs(time.altzone // 60) % 60)
'+0200'

正如 abarnert 在评论中提到的,time.altzone 在夏令时(DST)生效时给出偏移量,而 time.timezone 则是在夏令时不生效时给出偏移量。要确定使用哪个,你可以按照 J.F. Sebastian 在他对另一个问题的回答中建议的方法来做 这样你就可以得到正确的偏移量:

time.altzone if time.daylight and time.localtime().tm_isdst > 0 else time.timezone

他还建议你可以在 Python 3 中使用以下方法,通过 datetime.timezone 来获取你想要的格式:

>>> datetime.now(timezone.utc).astimezone().strftime('%z')
'+0200'

撰写回答