Django Timezone Gotcha

Dealing with timezones is always a pain. I thought I solved that problem by using:

from django.utils import timezone

now = timezone.now()

This code gets the time in the timezone specified in your Django settings… or so I thought. When you render the time in a template, it works as expected.

But in your python code, a view for example, the time is in UTC. From the Django docs:

You should only use local time when you’re interacting with humans, and the template layer provides filters and tags to convert datetimes to the time zone of your choice.

I agree with that. However, I interact with humans in other layers besides the template layer. For example, I dynamically generate files and put a human readable timestamp in the file. Many of my users do everything in one timezone. They never think about other time zones or UTC. So writing the timestamp in UTC would just seem overly geeky and annoying to them.

Here is how to get the datetime in the local timezone:


import pytz
import datetime
pytz.timezone(settings.TIME_ZONE).localize(datetime.datetime.now())

Mocking Django Timezone

I use django.utils.timezone.now() in a lot of my code. It returns the datetime in the timezone specified in settings.py. One side effect of using this function is that during testing, you may want “now()” to be a fixed date time. No worries. Mock to the rescue. Here is the code:

import datetime

from django.test import TestCase
from django.utils import timezone

import mock

# Make now() a constant
NOW_FOR_TESTING = datetime.datetime(2015, 10, 10, 10)


# This is the function that replaces django.utils.timezone.now()
def mocked_now():
    return NOW_FOR_TESTING


# This function shows that the mocking is in effect even outside of the TestMyTest scope.
def a_func():
    return timezone.now()


@mock.patch('django.utils.timezone.now', side_effect=mocked_now)
class TestMyTest(TestCase):
    def test_time_zone(self, *args):
        # After patching, mock passes in some extra vars. Put *args to handle them.
        self.assertEqual(timezone.now(), NOW_FOR_TESTING)
        self.assertEqual(timezone.now().date(), NOW_FOR_TESTING.date())
        self.assertEqual(mocked_now(), NOW_FOR_TESTING)