将日期字符串解析为带时区的日期时间

ama*_*ain 3 python datetime date-parsing

我有一个字符串:

r = 'Thu Dec 17 08:56:41 CST 2020'
Run Code Online (Sandbox Code Playgroud)

这里CST代表中国中部时间('亚洲/上海')。我想将它解析为日期时间...我正在做类似的事情

from dateparser import parse
r1 = parse(r)
Run Code Online (Sandbox Code Playgroud)

这给了我 r1 作为:

2020-12-17 08:56:41-06:00
Run Code Online (Sandbox Code Playgroud)

而且我也在做这个

r2 = r1.replace(tzinfo=pytz.timezone("Asia/Shanghai"))
Run Code Online (Sandbox Code Playgroud)

这给了我 r2 :

 2020-12-17 08:50:41+08:00
Run Code Online (Sandbox Code Playgroud)

r2 有 6 分钟的延迟有人能告诉我为什么吗?以及如何正确地将我的原始字符串 r1 传输到所需的 r2 ,即:

2020-12-17 08:56:41 in Asia/Shanghai timezone
Run Code Online (Sandbox Code Playgroud)

谢谢

bud*_*mat 5

使用dateutil.parser你可以直接正确解析你的日期。

请注意,这CST是一个不明确的时区,因此您需要指定您所指的时区。您可以直接在tzinfos调用的参数中执行此操作parse(),也可以定义一个具有时区映射的字典并传递它。在此字典中,您可以指定偏移量,例如

timezone_info = {
        "CDT": -5 * 3600,
        "CEST": 2 * 3600,
        "CST": 8 * 3600
}

parser.parse(r, tzinfos=timezone_info)
Run Code Online (Sandbox Code Playgroud)

或(使用gettz)直接指定时区:

timezone_info = {
        "CDT": gettz("America/Chicago"),
        "CEST": gettz("Europe/Berlin"),
        "CST": gettz("Asia/Shanghai")
}

parser.parse(r, tzinfos=timezone_info)
Run Code Online (Sandbox Code Playgroud)

另请参阅dateutil.parser 文档以及此问题的答案。

请注意,如果您所在的位置实行夏令时,则后一种方法会很棘手!根据您应用的日期,gettz("America/Chicago")结果将是 UTC-5 或 UTC-6(因为芝加哥在中部标准时间和中部夏令时间之间切换)。因此,根据您的输入数据,第二个示例实际上可能并不正确并产生错误的结果!目前,中国全年遵守中国标准时间 (CST),因此对于您的用例而言,这没有什么区别(但可能取决于您的日期范围)。

全面的:

from dateutil import parser
from dateutil.tz import gettz

timezone_info = {"CST": gettz("Asia/Shanghai")}

r = 'Thu Dec 17 08:56:41 CST 2020'
d = parser.parse(r, tzinfos=timezone_info)

print(d)
print(d.strftime('%Y-%m-%d %H:%M:%S %Z%z'))
Run Code Online (Sandbox Code Playgroud)

得到你

2020-12-17 08:56:41+08:00
2020-12-17 08:56:41 CST+0800
Run Code Online (Sandbox Code Playgroud)

编辑:使用这种方法打印人类可读的时区名称而不是缩写的名称只是稍微复杂一点,因为dateutil.tz.gettz()它会为您tzfile提供一个没有属性而只有名称的属性。_filename但是,您可以通过受保护的方式获取它split()

print(d.strftime('%Y-%m-%d %H:%M:%S') + " in " + "/".join(d.tzinfo._filename.split('/')[-2:]))
Run Code Online (Sandbox Code Playgroud)

产量

2020-12-17 08:56:41+08:00 in Asia/Shanghai
Run Code Online (Sandbox Code Playgroud)

当然,只有当您gettz()首先设置时区时,这才有效。

编辑 2:如果您知道所有日期均采用 CST,则您也可以在解析时忽略时区。这会让你得到天真的(或无意识的)日期时间,然后你可以在其中添加人类可读的时区。您可以使用replace()上面所示的方法gettz()或使用模块timezone(()中的方法来指定时区pytz

from dateutil import parser
from dateutil.tz import gettz
import pytz

r = 'Thu Dec 17 08:56:41 CST 2020'
d = parser.parse(r, ignoretz=True)

d_dateutil = d.replace(tzinfo=gettz('Asia/Shanghai'))
d_pytz = d.replace(tzinfo=pytz.timezone('Asia/Shanghai'))
Run Code Online (Sandbox Code Playgroud)

请注意,根据您使用哪个模块添加时区信息, 的类会tzinfo有所不同。对于该pytz对象,有一种更直接的方法以人类可读的形式访问时区:

print(type(d_dateutil.tzinfo))
print("/".join(d_dateutil.tzinfo._filename.split('/')[-2:]))

print(type(d_pytz.tzinfo))
print(d_pytz.tzinfo.zone)

Run Code Online (Sandbox Code Playgroud)

产生

<class 'dateutil.tz.tz.tzfile'>
Asia/Shanghai
<class 'pytz.tzfile.Asia/Shanghai'>
Asia/Shanghai
Run Code Online (Sandbox Code Playgroud)