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

16

每次我使用:

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。


1
我无法重现您所观察到的结果:In [2]: time.strftime("%z") Out[2]: '-0500'。您能否提供更多详细信息?因为您所说的与文档不一致。 (https://docs.python.org/3.4/library/time.html#time.strftime) - Patrick Collins
1
@PatrickCollins 我也没有得到偏移量,而是得到了“Mitteleuropäische Sommerzeit”(Windows 8,Python 2.7、3.3和3.4)。 - poke
3
很遗憾,Windows 下的库不支持 %z,而 Python 依赖这些库。请参考 http://msdn.microsoft.com/en-us/library/fe06s4ak.aspx。 - Mark Ransom
3
WindowsеҜ№дәҺ%zзҡ„й”ҷиҜҜз»“жһңжҳҜдёҖдёӘжңӘи§ЈеҶізҡ„bugпјҡhttp://bugs.python.org/issue20010 - Uyghur Lives Matter
这个bug基本上是在争论要将文档修改得更符合事实。对于那些对2.x感兴趣的人来说,文档甚至没有提到%z,所以问题根本就不会出现。 - abarnert
显示剩余4条评论
4个回答

8
在2.x版本中,如果您查看time.strftime的文档,它们甚至不会提到%z。它甚至不能保证存在,更不能在各个平台上保持一致。实际上,正如注1所示,这取决于C strftime函数。另一方面,在3.x中,他们确实提到了%z,而解释它不按预期工作的脚注并不容易看到;那是一个开放的错误
但是,在2.6+(包括所有3.x版本)中,datetime.strftime保证支持%z作为“形式为+HHMM或-HHMM的UTC偏移量(对象为空时为空字符串)”。因此,这就产生了一种非常简单的解决方法:使用datetime而不是time。如何更改取决于您试图做什么-使用Python-dateutil tz然后datetime.now(tz.tzlocal()).strftime('%z')是获取本地时区格式化为GMT偏移量的方式,但如果您尝试格式化完整时间,细节将有所不同。
如果您查看源代码,time.strftime基本上只检查格式字符串是否有效,并调用本机strftime函数,而datetime.strftime对于不同的说明符具有许多特殊处理,包括%z;特别是,它将用utcoffset的格式化版本替换%z,然后将其传递给strftime。自2.7以来,该代码已经更改了几次,甚至一次被彻底重新组织,但即使在3.5之前的主干中也基本存在相同的差异。

1
在Python 3中,仅使用标准库:datetime.now(timezone.utc).astimezone().strftime('%z') - jfs

7

为了得到正确的解决方案,请参见下面abarnert的答案


你可以使用time.altzone,它返回一个负的偏移秒数。例如,我现在是在中欧夏令时(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则是在DST不活动时。要确定使用哪个,您可以按照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'

我得收回之前的话,现在这段代码对我起作用了。我第一次可能没有完全复制你的文本。 - Raeven
@Raeven 很高兴听到这个消息 :) - poke
altzone是“本地DST时区的偏移量,以UTC为基准,单位为秒,如果定义了DST时区。如果本地DST时区在UTC东面(如西欧,包括英国),则此值为负数。仅在夏令时非零时使用。”当然,如果您特别要求“美国东部夏令时”,而不是“美国东部时间”,那么这就是正确的答案,但通常情况下,在具有DST的时区中,一半的时间是错误的,在没有时区的时区中则毫无用处。 - abarnert
@J.F.Sebastian:没错,time.daylight 表示时区是否存在(或曾经存在)夏令时。如果为真,则不知道在没有指定要查询的日期的情况下使用 altzone 还是 timezone。 (这并不奇怪,因为除非您知道要查询的日期,否则该问题毫无意义。) - abarnert
@abarnert: a) “ever” 是不正确的:即使时区过去曾经遵循夏令时,daylight 可能为零。b) 正如我所说,整个 [daylight] 方法不够灵活:例如,参见这里提到的 mercurial bug,“对于规则发生变化的年份,这些常量可能提供不正确的数据。” 要获取可靠的 UTC 偏移量,请参见我的答案(使用 pytz。c) 日期是隐含的。问题中的 time.strftime("%z") 适用于当前时间。 - jfs
显示剩余8条评论

4
使用time.timezone获取时间偏移量(以秒为单位)。
使用“:”格式化它。
("-" if time.timezone > 0 else "+") + time.strftime("%H:%M", time.gmtime(abs(time.timezone)))

将其转换为+/-HH:MM格式。

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

此外,我认为 这篇答案可能会帮助您将时区偏移字符串转换为HH:MM格式。但由于 "%z" 不如预期工作,所以我觉得它没有用。

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


考虑到问题是关于美国东部夏令时的偏移量,我认为他并不想要“免疫夏令时”的解决方案。(不幸的是,我认为这个问题没有明确说明他实际上想要什么,但我认为这不是他想要的。) - abarnert

0

毫不意外,这个错误在最新的 Windows 版本 Win 10 Version 1703 (Creators) 中仍然存在。不过,时间不停歇,有一个名为 pendulum 的美妙日期和时间库可以完成问题所要求的功能。产品的主要作者 Sébastien 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'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接