【问题标题】:Is datetime.replace fundamentally broken? [duplicate]datetime.replace 从根本上被破坏了吗? [复制]
【发布时间】: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)

标签: python datetime timezone pytz python-dateutil


【解决方案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

【讨论】:

    猜你喜欢
    • 2017-01-24
    • 1970-01-01
    • 2021-05-17
    相关资源
    最近更新 更多