如何使用 dateutil.tz.tz.tzoffset 本地化使用 strptime 创建的时区幼稚日期时间?

How can I use a dateutil.tz.tz.tzoffset to localize a timezone naive datetime created using strptime?

提问人:KyferEz 提问时间:5/17/2019 最后编辑:KyferEz 更新时间:5/17/2019 访问量:3383

问:

如何使用 dateutil.tz.tz.tzoffset 类型的对象来本地化具有正确时区和 DST 信息的时区幼稚 datetime 对象,以便将其正确转换为 UTC?或者,如何将 dateutil.tz.tz.tzoffset 转换为 pytz.timezone?

我无法找到有关使用 dateutil.tz.tz.tzoffset 对象本地化日期时间对象的好信息。请参阅下面,了解我评论过的一些更好的文章。

背景信息:

我正在处理许多日期字符串,其中大多数没有时区信息。在某些情况下,时间是格林威治标准时间,在其他情况下是本地时间。我必须首先确定创建这些不同日志的设备的时区,然后解析各种日期字符串,如果是本地时间,则添加添加时区,最后将其转换为 UTC。

我几乎都工作了,除了确定时区的唯一可靠方法是来自一个文本文件,该文件的日期格式为 EDT、IST 等,所以我使用了以下链接中投票最高的帖子来使用 dateutil 的 parser.parse() 函数并向它发送它的 tzinfos 参数的字典。(在 Python 中使用时区缩写名称解析日期/时间字符串?)

但是,这给我留下了一个具有 tzinfo type=dateutil.tz.tz.tzoffset 的 DateTime。这对我来说没关系,除了我需要使用这个 tzinfo 来本地化不包含时区信息的字符串,并且 dateutil.tz.tz.tzoffset 类型没有像 pytz.timezone 那样的本地化选项,这是我问题的症结所在。

我是不是太难了?我是否只是将时区幼稚日期时间中的 tzinfo 替换为我保存的 dateutil.tz.tz.tzoffset 对象?

法典:

下面读取日期字符串并将其保存为 datetime 对象,将时区保存在 var 中以供以后使用,然后将日期字符串转换为 UTC:

from dateutil.parser import parse as parsedate
import pytz
from pytz import timezone
from datetime import datetime

timestr = 'Sat, 5/01/2019 8:00PM EDT' #only reliable source of timezone info
dtfromstrEDT = parsedate(timestr, tzinfos=tzd) #tzd is created from the above link
mytimeZone = dtfromstrEDT.tzinfo  # save local timezone
dtUTC = dtfromstrEDT.astimezone(pytz.timezone('UTC'))  # convert to utc

现在,这是一个新的时区幼稚日期字符串。它是以与上述相同的本地时间(EDT)录制的,因此我想使用我保存的mytimeZone var对其进行本地化并转换为UTC。我使用标准的 strptime 将其作为幼稚的日期时间读入。但是,当使用 mytimeZone 本地化 Naive 日期时间时,它会失败。错误如下。我理解错误;但我不知道如何完成我需要的东西:

timestrnaive = 'Mar 15 12:09:20 2019' #in EDT time, same as above string but without any timezone info
dtfromstrNaive = datetime.strptime(timestrnaive, "%b %d %H:%M:%S %Y")
dtlocalized = mytimeZone.localize(dtfromstrNaive, is_dst=True)  
# the above is where it fails with provided error below
# however I can do this instead if I had a pytz.timezone object:
loc_tz = pytz.timezone('America/New_York')
dtlocalized = loc_tz.localize(dtfromstrNaive, is_dst=True) 
dtUTC2 = dtlocalized.astimezone(pytz.timezone('UTC'))  # convert to utc

错误:

Traceback (most recent call last):
  File "C:\Examples\timezones.py", line 221, in <module>
    dtlocalized = mytimeZone.localize(dtfromstrNaive, is_dst=True)  # convert to whatever tz is stored in self.timeZone
AttributeError: 'tzoffset' object has no attribute 'localize'

已查看以下内容:

从时区偏移量本地化日期时间(时区感知) - 我不确定如何将其应用于此问题,因为我有一个 dateutil.tz.tz.tzoffset 对象,而不是原始 utc 时间。

在 Python 中使用时区缩写名称解析日期/时间字符串?- 这让我可以读取时区数据,例如 EDT 和 PDT。

如何在 python 中使一个不知道的日期时间时区知道 - 这无济于事,因为它没有解决我提到的 dateutil.tz.tz.tzoffset 问题。

python 日期时间 pytz python-dateutil

评论


答:

1赞 KyferEz 5/17/2019 #1

经过更多的测试,我意识到我把它做得太难了。解决方案很简单:

timestrnaive = 'Mar 15 12:09:20 2019'
dtfromstrNaive = datetime.strptime(timestrnaive, "%b %d %H:%M:%S %Y") 
dtlocalized = dtfromstrNaive.replace(tzinfo=mytimeZone)
dtUTC2 = dtlocalized.astimezone(pytz.timezone('UTC'))  # convert to utc

7赞 Paul 5/17/2019 #2

你在这里怀有的主要误解是你需要这种方法,这是一个历史产物,可以追溯到 PEP 495 添加“fold”属性之前的时代。您可以在本文中详细了解偏离标准库界面的原因。localizepytzpytz

正如您在回答中所指出的,对于区域以外的任何内容,您可以简单地使用适当的时区来构建新的日期时间。还有一个dateutil.utils.default_tzinfo便利功能,可以自动检测日期时间是否幼稚,并在 if so 上附加默认值。pytz.replacetzinfo

另一件需要注意的事情是,你在这里的使用是不必要的,因为这里也提供了一个对象,所以你可以做这样的事情:pytzdateutilUTC

from dateutil import tz
timestrnaive = 'Mar 15 12:09:20 2019'
dtfromstrNaive = datetime.strptime(timestrnaive, "%b %d %H:%M:%S %Y") 
dtlocalized = dtfromstrNaive.replace(tzinfo=mytimeZone)
dtUTC2 = dtlocalized.astimezone(tz.UTC) # Convert to UTC

因此,您不需要对 保持任何依赖。pytz

如果你想了解更多关于在 Python 中使用时区的信息,我最近在 PyCon 上也做了一个关于这个问题的演讲

评论

0赞 KyferEz 5/21/2019
谢谢。当我需要像这样的代码时怎么样?我还能消除pytz吗?tz = “UTC” mytz = pytz.timezone(tz)
0赞 Paul 5/23/2019
是的,适用于“UTC”,我认为接受任何接受的东西。tz.gettz()pytz.timezone