Permalink
Browse files

Issue #4 : Expiry Time Calculated Incorrectly

Internal function to_datetime was expecting unix time in microseconds,
but the parser was providing a timestamp in milliseconds.

With this fix, we interpret the unix timestamp as UTC. The rdb file does
not store the timezone, so we cannot accurately convert it to the right
time. So, we cheat and use UTC always.
  • Loading branch information...
1 parent 41f6432 commit 176beb3a14c9d2fac7b90777068e089a03ad87e2 @sripathikrishnan committed Apr 22, 2012
Showing with 11 additions and 12 deletions.
  1. +3 −3 rdbtools/parser.py
  2. +2 −3 tests/create_test_rdb.py
  3. BIN tests/dumps/keys_with_expiry.rdb
  4. +6 −6 tests/parser_tests.py
View
@@ -281,10 +281,10 @@ def parse(self, filename):
data_type = read_unsigned_char(f)
if data_type == REDIS_RDB_OPCODE_EXPIRETIME_MS :
- self._expiry = to_datetime(read_unsigned_long(f))
+ self._expiry = to_datetime(read_unsigned_long(f) * 1000)
data_type = read_unsigned_char(f)
elif data_type == REDIS_RDB_OPCODE_EXPIRETIME :
- self._expiry = to_datetime(read_unsigned_int(f) * 1000)
+ self._expiry = to_datetime(read_unsigned_int(f) * 1000000)
data_type = read_unsigned_char(f)
if data_type == REDIS_RDB_OPCODE_SELECTDB :
@@ -697,7 +697,7 @@ def ntohl(f) :
def to_datetime(usecs_since_epoch):
seconds_since_epoch = usecs_since_epoch / 1000000
useconds = usecs_since_epoch % 1000000
- dt = datetime.datetime.fromtimestamp(seconds_since_epoch)
+ dt = datetime.datetime.utcfromtimestamp(seconds_since_epoch)
delta = datetime.timedelta(microseconds = useconds)
return dt + delta
View
@@ -3,7 +3,6 @@
import string
import shutil
import os
-from datetime import datetime
r = redis.StrictRedis()
r2 = redis.StrictRedis(db=2)
@@ -52,8 +51,8 @@ def empty_database() :
pass
def keys_with_expiry() :
- r.set("expires_ms_precision", "2022-12-25 10:11:12.000573")
- r.expireat("expires_ms_precision", 1671943272573)
+ r.set("expires_ms_precision", "2022-12-25 10:11:12.573 UTC")
+ r.execute_command('PEXPIREAT', "expires_ms_precision", 1671963072573)
def multiple_databases() :
r.set("key_in_zeroth_database", "zero")
Binary file not shown.
View
@@ -35,8 +35,8 @@ def test_keys_with_expiry(self):
self.assertEquals(expiry.year, 2022)
self.assertEquals(expiry.month, 12)
self.assertEquals(expiry.day, 25)
- #self.assertEquals(expiry.hour, 10)
- #self.assertEquals(expiry.minute, 11)
+ self.assertEquals(expiry.hour, 10)
+ self.assertEquals(expiry.minute, 11)
self.assertEquals(expiry.second, 12)
self.assertEquals(expiry.microsecond, 573000)
@@ -241,7 +241,7 @@ def end_hash(self, key):
raise Exception('start_hash not called for key = %s', key)
if len(self.currentdb()[key]) != self.lengths[self.dbnum][key] :
raise Exception('Lengths mismatch on hash %s, expected length = %d, actual = %d'
- % (key, self.lengths[self.dbnum][key], len(currentdb()[key])))
+ % (key, self.lengths[self.dbnum][key], len(self.currentdb()[key])))
def start_set(self, key, cardinality, expiry, info):
if key in self.currentdb() :
@@ -262,7 +262,7 @@ def end_set(self, key):
raise Exception('start_set not called for key = %s', key)
if len(self.currentdb()[key]) != self.lengths[self.dbnum][key] :
raise Exception('Lengths mismatch on set %s, expected length = %d, actual = %d'
- % (key, self.lengths[self.dbnum][key], len(currentdb()[key])))
+ % (key, self.lengths[self.dbnum][key], len(self.currentdb()[key])))
def start_list(self, key, length, expiry, info):
if key in self.currentdb() :
@@ -283,7 +283,7 @@ def end_list(self, key):
raise Exception('start_set not called for key = %s', key)
if len(self.currentdb()[key]) != self.lengths[self.dbnum][key] :
raise Exception('Lengths mismatch on list %s, expected length = %d, actual = %d'
- % (key, self.lengths[self.dbnum][key], len(currentdb()[key])))
+ % (key, self.lengths[self.dbnum][key], len(self.currentdb()[key])))
def start_sorted_set(self, key, length, expiry, info):
if key in self.currentdb() :
@@ -304,7 +304,7 @@ def end_sorted_set(self, key):
raise Exception('start_set not called for key = %s', key)
if len(self.currentdb()[key]) != self.lengths[self.dbnum][key] :
raise Exception('Lengths mismatch on sortedset %s, expected length = %d, actual = %d'
- % (key, self.lengths[self.dbnum][key], len(currentdb()[key])))
+ % (key, self.lengths[self.dbnum][key], len(self.currentdb()[key])))
def end_database(self, dbnum):
if self.dbnum != dbnum :

0 comments on commit 176beb3

Please sign in to comment.