`datetime.now(pytz_timezone)` 什么情况下会失败?

11

Delorean文档展示了在给定时区获取当前时间的方法,使用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)

将其与基于德洛雷安的代码进行比较:

from delorean import Delorean

EST = "US/Eastern"

d = Delorean(timezone=EST)

我认为应该将datetime示例写成:


from datetime import datetime
import pytz

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

有没有情况是第一个代码示例可以正常工作,而最后一个失败了?


更新: 当前示例:

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

这仍然太冗长。

问题依然存在:你是否需要通过 UTC 和 tz.normalize() 明确进行往返,或者可以直接使用 datetime.now(tz)


他的目标是在项目主页上提供一个例子,说明如何使用“Delorean”比使用“datetime”和“pytz”更加简洁。 这个例子很糟糕,因为代码有误,而且你的例子可以更好地处理它,但你的例子并没有达到最初的目标。也许可以提出一个新的例子,展示一个需要实际使用“localize”和“normalize”的情况,并说明如何使用“Delorean”更容易处理它? - heenenee
1
我在delorean上提交了一个问题(issue),所以他们创建了一个拉取请求(pull request),清理了第一个示例。(他们还清理了delorean示例。) - Patrick Maupin
@heenenee:我的问题是关于 datetime.now(tz):是否您可以始终使用它来返回给定时区的当前时间,而不是使用 est.normalize(utc.localize(datetime.uctnow()).astimezone(est)) - jfs
@PatrickMaupin: 这个合并的例子 仍然过于冗长。问题仍然存在:您是否需要通过 utc 和 tz.normalize() 进行显式的往返或者只需像问题中所示使用 datetime.now(tz)。我认为 datetime.now(tz) 就足够了,但是 Delorian的作者持不同意见 - jfs
我并不反对,但第一个例子让我感到困扰,因为它实际上并没有按照编码工作(正如下面的答案所指出的)。如果可以的话,最好先达成一致的目标再进行争论。 :) - Patrick Maupin
1个回答

11

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源代码中的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。 在这个方向上没有任何歧义,所以结果将是等效的。

值得注意的是,在 datetime文档 中指出,datetime.now相当于调用:

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

前面我展示了pytz中fromutc的源代码,但我不确定这是否与以下代码有任何区别:

tz.fromutc(datetime.utcnow())

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接