Python datetime strptime() 和 strftime():如何保留时区信息
看看下面的代码:
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 个回答
这是我在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
很遗憾,strptime()
这个函数只能处理你操作系统上设置的时区,而且实际上它只是作为时间偏移来使用。从文档中可以了解到:
对
%Z
这个指令的支持是基于tzname
中的值,以及daylight
是否为真。因此,这个功能是和平台相关的,除了能识别 UTC 和 GMT 这两个时区(它们总是被认为是非夏令时的时区)以外,其他的就不一定能用了。
而且,strftime()
这个函数并不正式支持 %z
。
所以,如果你想处理时区解析的话,恐怕得依赖 python-dateutil
这个库了。
这里的问题部分在于,通常用来表示时区的字符串并不是唯一的。比如“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()
把它解析出来。