使用时区将日期字符串解析为日期时间

Parse Date string to datetime with timezone

我有一个字符串:

r = 'Thu Dec 17 08:56:41 CST 2020'

这里CST代表中国中部时间('Asia/Shanghai')。我想将它解析为日期时间......我正在做类似

的事情
from dateparser import parse
r1 = parse(r)

哪个给我 r1 作为:

2020-12-17 08:56:41-06:00

我也在做这个

r2 = r1.replace(tzinfo=pytz.timezone("Asia/Shanghai"))

这给了我 r2 作为:

 2020-12-17 08:50:41+08:00

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

2020-12-17 08:56:41 in Asia/Shanghai timezone

谢谢

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

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

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

parser.parse(r, tzinfos=timezone_info)

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

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

parser.parse(r, tzinfos=timezone_info)

另见 dateutil.parser documentation and the answers to

请注意,如果您所在的位置采用夏令时,后一种方法会很棘手!根据您应用它的日期,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'))

得到你

2020-12-17 08:56:41+08:00
2020-12-17 08:56:41 CST+0800

编辑:使用这种方法打印人类可读的时区名称而不是缩写的名称只是稍微复杂一点,因为 dateutil.tz.gettz() 会让你得到一个 tzfile 没有只有名称的属性。但是,您可以使用 split():

通过受保护的 _filename 获取它
print(d.strftime('%Y-%m-%d %H:%M:%S') + " in " + "/".join(d.tzinfo._filename.split('/')[-2:]))

产量

2020-12-17 08:56:41+08:00 in Asia/Shanghai

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

编辑 2:如果您知道无论如何您的所有日期都在 CST 中,您也可以在解析时忽略时区。这会让你获得天真的(或无意识的)日期时间,然后你可以在其中添加一个人类可读的时区。您可以使用 replace() 执行此操作,并使用 gettz() 或使用 pytz 模块中的 timezone(() 指定时区:

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'))

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

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

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

产生

<class 'dateutil.tz.tz.tzfile'>
Asia/Shanghai
<class 'pytz.tzfile.Asia/Shanghai'>
Asia/Shanghai
from datetime import datetime
import pytz

# The datetime string you have
r = "Thu Dec 17 08:56:41 CST 2020"

# The time-zone string you want to use
offset_string = 'Asia/Shanghai'

# convert the time zone string into offset from UTC
#    a. datetime.now(pytz.timezone(offset_string)).utcoffset().total_seconds() --- returns seconds offset from UTC
#    b. convert seconds into hours (decimal) --- divide by 60 twice
#    c. remove the decimal point, we want the structure as: +0800
offset_num_repr = '+{:05.2f}'.format(datetime.now(pytz.timezone(offset_string)).utcoffset().total_seconds()/60/60).replace('.', '')
print('Numeric representation of the offset: ', offset_num_repr)

# replace the CST 2020 with numeric timezone offset
#    a. replace it with the offset computed above
updated_datetime = str(r).replace('CST', offset_num_repr)
print('\t    Modified datetime string: ', updated_datetime)

# Now parse your string into datetime object
r = datetime.strptime(updated_datetime, "%a %b %d %H:%M:%S %z %Y")
print('\tFinal parsed datetime object: ', r)

应该产生:

Numeric representation of the offset:  +0800
            Modified datetime string:  Thu Dec 17 08:56:41 +0800 2020
        Final parsed datetime object:  2020-12-17 08:56:41+08:00