datetime.replace从根本上被打破了吗?

时间:2017-07-21 16:06:58

标签: python datetime timezone pytz python-dateutil

将时区天真日期时间转换为特定时区会产生完全错误的结果。

import dateutil as du
import pytz    
du.parser.parse('2017-05-31T15:00:00').replace(tzinfo=pytz.timezone('Europe/London')).isoformat()

返回一分钟而非一小时的偏移量与UTC

相比
'2017-05-31T15:00:00-00:01'

我之前看过一些日期时间的特点,但这一点令人叹为观止。

2 个答案:

答案 0 :(得分:1)

我经常使用replace() tzinfo对象运气不好。然而,我发现这个结构是可靠的:

代码:

def naive_to_aware(ts, tz):
    return tz.localize(ts)

从评论更新:

来自(pytz DOCS

  

不幸的是,对于许多时区,使用标准日期时间构造函数的'tzinfo参数''与pytz不起作用。

     

对于没有夏令时转换的时区,例如UTC

,这是安全的

所以它不只是运气不好,对于带有DST的时区的pytz对象来说是个问题。

测试代码:

import dateutil as du
import pytz

print(naive_to_aware(du.parser.parse('2017-05-31T15:00:00'),
                     pytz.timezone('Europe/London')).isoformat())

结果:

2017-05-31T15:00:00+01:00

答案 1 :(得分:1)

这里的主要问题是您使用的是pytz时区。 pytz区域不遵循tzinfo界面,不能简单地附加到datetime对象(通过构造函数或通过replace)。如果您想使用pytz个时区,则应使用pytz.timezone.localize与天真datetime。如果datetime已经知道时区,您可以使用datetime.astimezone在区域之间进行转换。

from dateutil import parser
import pytz

LON = pytz.timezone('Europe/London')
dt = parser.parse('2017-05-31T15:00:00')
dt = LON.localize(dt) 

print(dt)   # 2017-05-31 15:00:00+01:00

这是因为pytz的界面使用localize将静态时区附加到datetime。出于同样的原因,如果您对现在已本地化的datetime对象进行算术运算,则可能会产生类似的不正确结果,您必须使用pytz.timezone.normalize来修复它。这样做的原因是,从历史上看,使用Pythonic tzinfo接口处理模糊日期时间是不可能的,该接口在Python 3.6中使用PEP 495更改,使得pytz'解决方法不太必要。

如果您想使用tzinfo或构造函数将datetime传递给replace,或者您希望使用pythonic界面,dateutil的时间zone suite实现符合PEP 495的tzinfo接口。使用dateutil区域的等价物是:

from dateutil import parser
from dateutil import tz

LON = tz.gettz('Europe/London')
dt = parser.parse('2017-05-31T15:00:00').replace(tzinfo=LON)

print(dt)   # 2017-05-31 15:00:00+01:00