jamesls/fakeredis

TypeError: can't compare offset-naive and offset-aware datetimes

TvoroG opened this issue · 2 comments

Hi! Thanks for fakeredis!

There is a problem with timezone-aware datetimes. This test will fail on fakeredis but it pass on real one:

def test_expire_should_expire_key_by_aware_datetime(self):
    from datetime import timezone
    self.redis.set('foo', 'bar')
    self.assertEqual(self.redis.get('foo'), b'bar')
    self.redis.expireat('foo', datetime.utcnow().replace(tzinfo=timezone.utc) + timedelta(seconds=1))
    sleep(1.5)
    self.assertEqual(self.redis.get('foo'), None)
======================================================================
ERROR: test_expire_should_expire_key_by_aware_datetime (test_fakeredis.TestFakeRedis)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/fakeredis/test_fakeredis.py", line 2678, in test_expire_should_expire_key_by_aware_datetime
    self.redis.set('foo', 'bar')
  File "/fakeredis/fakeredis.py", line 315, in get
    value = self._db.get(name)
  File "/.virtualenvs/fakeredis/lib/python3.5/_collections_abc.py", line 597, in get
    return self[key]
  File "/fakeredis/fakeredis.py", line 116, in __getitem__
    self._update_expired_keys()
  File "/fakeredis/fakeredis.py", line 150, in _update_expired_keys
    if now > self._ex_keys[key]:
TypeError: can't compare offset-naive and offset-aware datetimes

A patch is certainly welcome, but I think redis-py will also do the wrong thing with an offset-aware datetime: it turns it into a UNIX timestamp using

            when = int(mod_time.mktime(when.timetuple()))

and mktime assumes local time.

The best thing might be to first get a fix into redis-py so that it correctly deals with offset-aware datetimes, and then fakeredis can mimic the behaviour.

I think fakeredis probably needs a bit of an overhaul in its timestamp handling: it seems to use local time, which will do interesting things at DST changeovers.

Should be fixed in 1.0rc1, because datetime handling is now handled by redis-py itself before fakeredis sees it.