Python datetime.replace是否根本损坏?

Python datetime.replace是否根本损坏?,python,datetime,timezone,pytz,python-dateutil,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' 我以前见过一些datetime特性,但这一个令人惊叹。我经常在使用对象

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

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'

我以前见过一些datetime特性,但这一个令人惊叹。

我经常在使用对象时运气不佳。然而,我发现这种结构是可靠的:

代码: 根据评论更新: 从()

不幸的是,对于许多时区,使用标准datetime构造函数的tzinfo参数“不适用于”pytz

不过,对于没有夏令时转换的时区(如UTC),它是安全的

因此,这不仅仅是运气不好,对于时区有DST的pytz对象来说是有问题的

测试代码: 结果:
这里的主要问题是您使用的是
pytz
时区
pytz
区域不遵循
tzinfo
界面,不能简单地附加到
datetime
对象(通过构造函数或
replace
)。如果你想使用
pytz
时区,你应该使用一个朴素的
datetime
。如果
datetime
已识别时区,则可以使用在区域之间进行转换

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
接口来处理不明确的日期时间是不可能的,而python3.6中的接口发生了变化,使得
pytz
的解决方法变得不那么必要

如果您希望使用
replace
或构造函数将
tzinfo
传递给
datetime
,或者您希望使用pythonic接口,
dateutil
的时区套件实现符合PEP 495的
tzinfo
接口。使用分区的等效值为:


不太清楚为什么会立即投票否决,没有任何评论。什么是dateutil(第三方库,不是像datetime这样的标准库)?解析后的结果是什么?这是一个相当广为人知的问题。Parse生成一个标准的datetime对象。您可以将
Parse
的输出添加到问题中吗?查看问题所在将很有帮助。使用tzinfo兼容的时区界面,如
dateutil.tz
,或使用
pytz.timezone(“欧洲/伦敦”)。本地化(my_datetime)
。这不是“坏运气”。pytz文档在接近开头的地方指出:该库不同于用于tzinfo实现的文档化Python API。它接着指出,使用pytz时区的一种方法是使用
astimezone
方法,如果它具有夏令时转换,则应特别避免将其用作
tzinfo
参数。它明确表示UTC对于
tzinfo
是安全的。因此,您似乎已经基本上自己发现了pytz文档推荐的内容@约翰尼,非常感谢你提供的信息。一个不兼容的API肯定会解释为什么我认为这是运气。。。更新以反映原因。@stephernauch您的第一段代码与
完全不同。替换(tzinfo=tz)
replace
只需附加
tzinfo
,而不修改时间。您的代码假定代码已在UTC中。如果您有一个简单的
datetime
表示,例如东部时间,并且您只想在其上附加一个区域,那么这将给出错误的答案。请注意,我投了反对票,因为这是错误和误导性的。如果/当它被编辑时,我很乐意收回。
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
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
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