3

I'm working with a testcase where an organization can be suspended. Currently I'm using freezegun to freeze a firm time, which is a datetime.datetime object with tzinfo=pytz.UTC.

In the test below you'll see a print of self.fake_datetime which returns a tzaware datetime: 2000-01-01 00:00:00+00:00.

When the test runs, I keep getting the famous RuntimeWarning:

/usr/local/lib/python2.7/dist-packages/django/db/models/fields/init.py:1447: RuntimeWarning: DateTimeField Organization.suspended received a naive datetime (2000-01-01 00:00:00) while time zone support is active. RuntimeWarning)

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))

I've been playing around with the freezegun timezone examples without any success to remove the runtime warning.

Any suggestions on how this should be resolved properly? I'd like to keep using Freezegun for this without a RuntimeWarning. Suppressing is an option, but I'd prefer not to.

update -- Solution based on the answer of xyres

Service was saving the datetime timezone unaware. Old situation commented and new situation is the actual code. I was thinking to much about mocking and assumed that the datetime saved in the service would be mocked with the timezone aware datetime object from the testcase by freezegun - which is not the case.

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()
4

1 回答 1

3

Seems like you're trying to save an object with a timezone-naive datetime. To get rid of this warning, just use timezone-aware datetime everywhere in your application.


Instead of managing timezone yourself manually using pytz, you can use Django's timezone module found at django.utils.timezone . It has some shortcut methods that you can use to convert naive datetime to aware datetime.

An advantage of using this is that if you ever change the timezone settings in your settings file, it will automatically pick the new timezone, whereas with pytz you'll have to manually update the new timezone everywhere.

from django.utils import timezone

fake_datetime = timezone.make_aware(timezone.datetime(2000, 1, 1, 0, 0, 0))
于 2018-05-09T22:26:54.503 回答