Freezegun 总是导致 RuntimeWarning 收到天真的日期时间

Posted

技术标签:

【中文标题】Freezegun 总是导致 RuntimeWarning 收到天真的日期时间【英文标题】:Freezegun always causes RuntimeWarning of receiving naive datetime 【发布时间】:2018-10-20 02:32:55 【问题描述】:

我正在处理一个可以暂停组织的测试用例。 目前我正在使用freezegun 来冻结一个固定时间,这是一个datetime.datetime 对象与tzinfo=pytz.UTC

在下面的测试中,您将看到self.fake_datetime 的打印,它返回tzaware 日期时间:2000-01-01 00:00:00+00:00

当测试运行时,我不断得到著名的RuntimeWarning

/usr/local/lib/python2.7/dist-packages/django/db/models/fields/init.py:1447: RuntimeWarning: DateTimeField Organization.suspended 收到一个天真的日期时间( 2000-01-01 00:00:00),而时区支持处于活动状态。 运行时警告)

import datetime
import pytz

from freezegun import freeze_time
# crop

class OrganizationSuspendTestCase(TestCase):

    def setUp(self):
        self.organization = OrganizationFactory()
        self.fake_datetime = datetime.datetime(2000, 1, 1, 0, 0, 0, tzinfo=pytz.UTC)
        print self.fake_datetime

    def test_suspend_organization(self):
        """
        Case: An organization is being suspended with the suspend service.
        Expected: The organization is updated with the suspending datetime and the reason.
        """
        with freeze_time(self.fake_datetime):
            mc_organization.services.organization.suspend(organization=self.organization, reason="Did not pay the bill")

        self.assertEqual(self.organization.suspended, datetime.datetime(2000, 1, 1, 0, 0, 0))

我一直在玩freezegun timezone examples,但没有成功删除运行时警告。

关于如何正确解决此问题的任何建议?我想在没有RuntimeWarning 的情况下继续使用Freezegun。抑制是一种选择,但我不想这样做。

更新 -- 基于answer of xyres的解决方案

服务在不知情的情况下保存了日期时间时区。旧情况注释,新情况是实际代码。我想了很多关于mocking 并假设保存在service 中的日期时间将被freezegun 测试用例中的时区感知日期时间对象模拟 - 事实并非如此。

def suspend(organization, reason):
    """
    Suspend an organization with the given reason.
    :param mc_organization.models.Organization organization: The organization to suspend.
    :param string reason: The reason of the suspending.
    :return: None
    """
    # organization.suspended = datetime.datetime.now() (Old sitation)
    organization.suspended = timezone.now()  # timezone aware situation.
    organization.suspended_reason = reason
    organization.save()

【问题讨论】:

作为一种快捷方式,您可以将这一行 - timezone.make_aware(datetime.datetime.now()) - 替换为 timezone.now(),这将自动返回可识别时区的 now 时间。 【参考方案1】:

好像你是trying to save an object with a timezone-naive datetime。要消除此警告,只需在应用程序中的任何位置使用时区感知日期时间即可。


您可以使用位于django.utils.timezone 的Django 的timezone 模块,而不是使用pytz 自己手动管理时区。它有一些快捷方法,可用于将天真的日期时间转换为有意识的日期时间。

使用此功能的一个优点是,如果您在设置文件中更改时区设置,它将自动选择新时区,而使用 pytz 您将不得不在任何地方手动更新新时区。

from django.utils import timezone

fake_datetime = timezone.make_aware(timezone.datetime(2000, 1, 1, 0, 0, 0))

【讨论】:

感谢您的解决方案。我期待 datetime 对象在测试期间被 freezegun 模拟,这是一个不正确的假设。我已经根据您的回答更新了我的问题,并描述了我的错误假设。

以上是关于Freezegun 总是导致 RuntimeWarning 收到天真的日期时间的主要内容,如果未能解决你的问题,请参考以下文章

取消引用已删除的指针总是会导致访问冲突?

不兼容的 CoreData 存储是不是总是导致崩溃?

失去理智导致获取核心数据总是返回错误

不总是导致程序崩溃的预期缓冲区溢出

试图输出数学方程的解总是导致 0

在 setContentView() 之前调用 findViewById() 会导致 NullPointerException 但并非总是如此? [复制]