Python datetime strptime() 和 strftime():如何保留时区信息

51 投票
4 回答
172930 浏览
提问于 2025-04-17 15:10

看看下面的代码:

import datetime
import pytz

fmt = '%Y-%m-%d %H:%M:%S %Z'

d = datetime.datetime.now(pytz.timezone("America/New_York"))
d_string = d.strftime(fmt)
d2 = datetime.datetime.strptime(d_string, fmt)
print d_string 
print d2.strftime(fmt)

输出结果是:

2013-02-07 17:42:31 EST
2013-02-07 17:42:31 

时区信息在转换过程中就消失了。

如果我把'%Z'换成'%z',我得到的结果是:

ValueError: 'z' is a bad directive in format '%Y-%m-%d %H:%M:%S %z'

我知道可以使用python-dateutil这个库,但我觉得很奇怪,为什么在datetime里不能实现这个简单的功能,还要引入更多的依赖?

4 个回答

4

这是我在Python 2.7中的回答

打印当前时间和时区

from datetime import datetime
import tzlocal  # pip install tzlocal

print datetime.now(tzlocal.get_localzone()).strftime("%Y-%m-%d %H:%M:%S %z")

打印当前时间和特定时区

from datetime import datetime
import pytz # pip install pytz

print datetime.now(pytz.timezone('Asia/Taipei')).strftime("%Y-%m-%d %H:%M:%S %z")

它会打印出类似这样的内容

2017-08-10 20:46:24 +0800
11

很遗憾,strptime() 这个函数只能处理你操作系统上设置的时区,而且实际上它只是作为时间偏移来使用。从文档中可以了解到:

%Z 这个指令的支持是基于 tzname 中的值,以及 daylight 是否为真。因此,这个功能是和平台相关的,除了能识别 UTC 和 GMT 这两个时区(它们总是被认为是非夏令时的时区)以外,其他的就不一定能用了。

而且,strftime() 这个函数并不正式支持 %z

所以,如果你想处理时区解析的话,恐怕得依赖 python-dateutil 这个库了。

33

这里的问题部分在于,通常用来表示时区的字符串并不是唯一的。比如“EST”这个缩写,在北美的人看来它指的是“America/New_York”,但在其他地方可能就不一定了。这是C语言时间API的一个局限,而Python的解决办法是……在未来的某个版本中添加完整的时区功能,只要有人愿意写相关的提案(PEP)。

你可以把时区格式化成一个偏移量,但这样就会丢失夏令时的信息(例如,在夏天你无法区分“America/Phoenix”和“America/Los_Angeles”)。你也可以把时区格式化成一个三字母的缩写,但从这个缩写中你无法再解析出原来的信息。

如果你想要一些模糊不清但通常又是你想要的东西,你需要使用像dateutil这样的第三方库。

如果你想要的是完全明确的时区信息,可以自己把实际的时区名称加到本地日期时间字符串后面,然后在另一端再分开:

d = datetime.datetime.now(pytz.timezone("America/New_York"))
dtz_string = d.strftime(fmt) + ' ' + "America/New_York"

d_string, tz_string = dtz_string.rsplit(' ', 1)
d2 = datetime.datetime.strptime(d_string, fmt)
tz2 = pytz.timezone(tz_string)

print dtz_string 
print d2.strftime(fmt) + ' ' + tz_string

或者……在这两者之间,你已经在使用pytz库,它可以解析像“EST”这样的格式(根据一些任意但明确的消歧义规则)。所以,如果你真的想这样做,可以在格式化时保留%Z,然后在传递其余部分给strptime之前,先用pytz.timezone()把它解析出来。

撰写回答