`datetime.now(pytz timezone)` 啥时候失败?

Posted

技术标签:

【中文标题】`datetime.now(pytz timezone)` 啥时候失败?【英文标题】:when does `datetime.now(pytz_timezone)` fail?`datetime.now(pytz timezone)` 什么时候失败? 【发布时间】:2015-10-31 10:25:29 【问题描述】:

delorean docs 显示这种方式获取给定时区的当前时间 using datetime:

from datetime import datetime
from pytz import timezone

EST = "US/Eastern"
UTC = "UTC"

d = datetime.utcnow()
utc = timezone(UTC)
est = timezone(EST)
d = utc.localize(d)
d = est.normalize(EST)

并将其与基于 delorian 的代码进行比较:

from delorean import Delorean

EST = "US/Eastern"

d = Delorean(timezone=EST)

I believedatetime 的例子应该写成:

from datetime import datetime
import pytz

eastern_timezone = pytz.timezone("US/Eastern")
d = datetime.now(eastern_timezone)

这样更简洁。

是否存在最后一个代码示例失败而第一个代码示例继续工作的情况?


更新: the current example:

from datetime import datetime
import pytz

d = datetime.utcnow()
d = pytz.utc.localize(d)

est = pytz.timezone('US/Eastern')
d = est.normalize(d)
return d

这还是太冗长了。

问题依旧:do you need the explicit round-trip via utc and tz.normalize() or can you use datetime.now(tz) instead?

【问题讨论】:

他的目标是在项目主页上举例说明使用Delorean 比使用datetimepytz 更干净。这是一个糟糕的示例,因为它是不正确的代码,并且可以通过您的示例更好地处理,但是您的示例不符合最初的目标。也许提出一个新的例子来说明localizenormalize实际上是必要的,以及如何使用Delorean更容易处理? 我向 delorean 提交了一个 issue,因此他们创建了一个 pull request 来清理第一个示例。 (他们还清理了 delorean 示例。) @heenenee:我的问题是关于datetime.now(tz):你是否总是可以使用它来返回给定时区的当前时间,而不是est.normalize(utc.localize(datetime.uctnow()).astimezone(est)) @PatrickMaupin:the merged example 仍然过于冗长。问题仍然存在:您是否需要通过 UTC 和 tz.normalize() 进行显式往返,或者您可以只使用 datetime.now(tz),如问题所示。我认为datetime.now(tz) 就足够了,但delorian's author disagrees 我不反对,但第一个例子让我很困扰,因为它实际上并没有像编码那样工作(如下面的答案所示)。认为如果有意义的话,最好为分歧达成一致的目标:) 【参考方案1】:

datetime.now(pytz_timezone) 什么时候失败?

据我所知,没有可能失败的情况。 datetime.now 在参数中传递的tzinfo 实例上调用fromutc 函数。从 UTC 到本地时间的所有转换都是明确的,因此没有失败的机会。

而且,原来的代码甚至不能工作。

d = est.normalize(EST)

这似乎将一个字符串作为唯一参数传递给normalize,该参数旨在采用datetime。这给出了:

AttributeError: 'str' object has no attribute 'tzinfo'

我相信他们打算写:

d = est.normalize(d.astimezone(est))

也就是说,我不认为他们代码的冗长增加了太多价值。正如您所指出的,只需一步即可轻松完成:

d = datetime.now(est)

查看cpython source code for datetime.now,我可以看到当提供tzinfo 对象时,它会调用该对象上的fromutc 方法。

if (self != NULL && tz != Py_None) 
    /* Convert UTC to tzinfo's zone. */
    PyObject *temp = self;

    self = _PyObject_CallMethodId(tz, &PyId_fromutc, "O", self);
    Py_DECREF(temp);

然后,在 pytz 源代码中,我看到 fromutc 方法的实现方式不同,具体取决于区域是 pytz.UTCStaticTzInfo 的实例还是 DstTzInfo。在所有三种情况下,从输入 UTC 值到目标时区的转换是明确的。这是DstTzInfo 的实现,是三个中更复杂的一个:

def fromutc(self, dt):
    '''See datetime.tzinfo.fromutc'''
    if (dt.tzinfo is not None
        and getattr(dt.tzinfo, '_tzinfos', None) is not self._tzinfos):
        raise ValueError('fromutc: dt.tzinfo is not self')
    dt = dt.replace(tzinfo=None)
    idx = max(0, bisect_right(self._utc_transition_times, dt) - 1)
    inf = self._transition_info[idx]
    return (dt + inf[0]).replace(tzinfo=self._tzinfos[inf])

这似乎会找到从_utc_transition_times 的时区转换,然后将其应用于返回的datetime。这个方向没有歧义,所以结果是等价的。

另外值得注意的是,在the datetime docs 中它说datetime.now 相当于调用:

tz.fromutc(datetime.utcnow().replace(tzinfo=tz))

鉴于我之前在 pytz 中显示的fromutc 的来源,我不确定这是否与以下内容有什么不同:

tz.fromutc(datetime.utcnow())

但无论哪种情况,我认为localizenormalize 都是不必要的。

【讨论】:

以上是关于`datetime.now(pytz timezone)` 啥时候失败?的主要内容,如果未能解决你的问题,请参考以下文章

python模块-pytz时区转换

pytz 和 datetime 奇怪的行为 - 可能的错误?

时区感知日期

Python Pytz美国/太平洋时区问题[重复]

使用pytz的python时区转换问题

pytz 为“非洲/喀土穆”提供错误的时区偏移