datetime.replace 从根本上被破坏了吗? [复制]
Posted
技术标签:
【中文标题】datetime.replace 从根本上被破坏了吗? [复制]【英文标题】:Is datetime.replace fundamentally broken? [duplicate] 【发布时间】:2017-12-27 18:33:17 【问题描述】:将时区原始日期时间转换为特定时区会产生完全错误的结果。
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'
我以前见过一些日期时间的特殊性,但这个令人叹为观止。
【问题讨论】:
不太清楚为什么这需要立即投反对票而不发表评论。 什么是 dateutil(第三方库,不在标准库中,如 datetime)?parse
之后的结果是什么?
这是一个相当知名的package。 Parse 生成一个标准的日期时间对象。
您可以将parse
的输出添加到问题中吗?看看问题出在哪里会很有帮助。
要么使用符合 tzinfo 的时区接口,例如 dateutil.tz
,要么使用 pytz.timezone("Europe/London").localize(my_datetime)
。
【参考方案1】:
我经常在使用replace()
和tzinfo
对象时运气不好。然而,我发现这个结构是可靠的:
代码:
def naive_to_aware(ts, tz):
return tz.localize(ts)
评论更新:
来自 (pytz DOCS)
不幸的是,在许多时区使用标准日期时间构造函数的 tzinfo 参数“不起作用”。
但对于没有夏令时转换的时区是安全的,例如 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
【讨论】:
这不是“倒霉”。 pytz 文档指出,接近开头:此库不同于用于 tzinfo 实现的文档化 Python API。它继续说明使用 pytz 时区的一种方法是使用astimezone
方法,如果它具有夏令时转换,则应特别避免将其用作 tzinfo
参数。它明确表示 UTC 对于tzinfo
是安全的。因此,您似乎基本上已经自己发现了 pytz 文档的建议。 ;)
@JohnY,非常感谢您提供的信息。一个不兼容的 API 肯定会解释为什么我只是认为这是运气...更新以反映 为什么。
@StephenRauch 您的第一段代码所做的事情与.replace(tzinfo=tz)
完全不同。 replace
只是附加tzinfo
而不修改时间。您的代码假定代码已经采用 UTC。如果你有一个幼稚的 datetime
代表,这将给出错误的答案,例如东部时间,您只想为其附加一个区域。
注意,我投了反对票,因为这是错误的和误导性的。如果/当它被编辑,我很高兴撤回。【参考方案2】:
这里的主要问题是您使用的是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
的变通方法不太必要。
如果您想使用replace
或构造函数将tzinfo
传递给datetime
,或者您更喜欢使用pythonic 接口,dateutil
的时区套件实现了符合 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
【讨论】:
以上是关于datetime.replace 从根本上被破坏了吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
Android CardView 圆角在 27 之前在 Android API 上被破坏
通知 DeleteIntent 在更高版本的 Android 上被破坏
Interface Builder 在使用 Cocoapods 1.0 的框架项目上被破坏