title: Best way of patching datetime in Django unit tests
body: <p>I am using a home brew <code>datetime.datetime</code> mock to patch out datetime throughout the code (see at the very bottom), but other people seem to hit problems understanding how it works, and hit unexpected problems. Considered the following test:</p>
  
  <pre><code>@patch("datetime.datetime", FakeDatetime)
  def my_test(self):
    FakeDatetime.now_value = datetime(2014, 04, 02, 13, 0, 0)
  
    u = User.objects.get(x=y)
    u.last_login = datetime(2014, 04, 01, 14, 0, 0)
    u.save()
  
    u2 = User.objects.get(x=y)
    # Checks if datetime.datetime.now() - u2.last_login &lt; 24 hours
    self.assertTrue(u2.logged_in_in_last_24_hours())
  </code></pre>
  
  <p>Now if you look at how Django DatetimeField serializes dates to SQL:</p>
  
  <pre><code>def to_python(self, value):
    if value is None:
      return value
    if isinstance(value, datetime.datetime):
      return value
    if isinstance(value, datetime.date):
      value = datetime.datetime(value.year, value.month, value.day)
  </code></pre>
  
  <p><a href="https://github.com/django/django/blob/1.5.1/django/db/models/fields/__init__.py#L771" rel="nofollow">Source</a></p>
  
  <p>This part gets executed as you call <code>u.save()</code> in the test.
  As this point in the Django code value of <code>value</code> (<code>u.last_login</code>) is of type <code>datetime.datetime</code> because we've assigned the value in the test using an unpatched version of datetime (since our import is
  at the module level, and the patch is at the method level).</p>
  
  <p>Now in the Django code, <code>datetime.datetime</code> is patched, therefore:</p>
  
  <pre><code>isinstance(value, datetime.datetime)
  </code></pre>
  
  <p>is equivalent to:</p>
  
  <pre><code>isinstance(datetime.datetime(2014, 04, 01, 14, 0, 0), FakeDatetime)
  </code></pre>
  
  <p>which is False, but:</p>
  
  <pre><code>isinstance(datetime.datetime(2014, 04, 01, 14, 0, 0), datetime.date)
  </code></pre>
  
  <p>is True hence the <code>datetime.datetime</code> object gets converted to a
  <code>datetime.date</code>, and when you retrieve <code>u2.last_login</code> from the SQL, the value is
  actually <code>datetime(2014, 04, 01, 0, 0, 0)</code> and not <code>datetime(2014, 04, 01, 14, 0, 0)</code></p>
  
  <p>Hence the tests fail.</p>
  
  <p>The way around this is to replace:</p>
  
  <pre><code>u.date_joined = datetime(2014, 04, 01, 14, 0, 0)
  </code></pre>
  
  <p>with:</p>
  
  <pre><code>u.date_joined = FakeDatetime(2014, 04, 01, 14, 0, 0)
  </code></pre>
  
  <p>but this seems prone to mistakes and tends to confuse people using or writing the tests.</p>
  
  <p>Especially in cases where you need the real <code>now</code> value you have to either do <code>datetime_to_fakedatetime(datetime.datetime.now())</code> or call <code>FakeDatetime.now()</code> but make sure that the previous test has unset the <code>FakeDatetime.now_value</code>.</p>
  
  <p>I am looking for a way to make this more intuitive, but at the same time avoid having to patch the <code>datetime.datetime</code> objects in particular sub modules (as there might be many of them), and just patch it throughout the code.</p>
  
  <p>Code for the homebrew mock:</p>
  
  <pre><code>from datetime import datetime
  
  class FakeDatetime(datetime):
    now_value = None
  
    def __init__(self, *args, **kwargs):
      return super(FakeDatetime, self).__init__()
  
    @classmethod
    def now(cls):
      if cls.now_value:
        result = cls.now_value
      else:
        result = datetime.now()
      return datetime_to_fakedatetime(result)
  
    @classmethod
    def utcnow(cls):
      if cls.now_value:
        result = cls.now_value
      else:
        result = datetime.utcnow()
      return datetime_to_fakedatetime(result)
  
    # http://stackoverflow.com/questions/20288439/how-to-mock-the-operator-in-python-specifically-datetime-date-datetime-ti
    def __add__(self, other):
      return datetime_to_fakedatetime(super(FakeDatetime, self).__add__(other))
  
    def __sub__(self, other):
      return datetime_to_fakedatetime(super(FakeDatetime, self).__sub__(other))
  
    def __radd__(self, other):
      return datetime_to_fakedatetime(super(FakeDatetime, self).__radd__(other))
  
    def __rsub__(self, other):
      return datetime_to_fakedatetime(super(FakeDatetime, self).__rsub__(other))
  
  
  def datetime_to_fakedatetime(dt):
    # Because (datetime - datetime) produces a timedelta, so check if the result is of the correct type.
    if isinstance(dt, datetime):
      return FakeDatetime(
        dt.year,
        dt.month,
        dt.day,
        dt.hour,
        dt.minute,
        dt.second,
        dt.microsecond,
        dt.tzinfo
      )
    return dt
  </code></pre>
  
  <p>Thanks!</p>