PYTHON-452 - Fix Cython deserializer date overflow with large timestamp

This commit is contained in:
Alan Boudreault
2016-02-08 11:12:12 -05:00
parent e805cd4707
commit 713bfe4223
5 changed files with 79 additions and 3 deletions

View File

@@ -35,10 +35,15 @@ from cassandra.util import is_little_endian
import_datetime()
DEF DAY_IN_SECONDS = 86400
DATETIME_EPOC = datetime.datetime(1970, 1, 1)
cdef datetime_from_timestamp(double timestamp):
cdef int seconds = <int> timestamp
cdef int microseconds = (<int64_t> (timestamp * 1000000)) % 1000000
return DATETIME_EPOC + timedelta_new(0, seconds, microseconds)
cdef int days = <int> (timestamp / DAY_IN_SECONDS)
cdef int64_t days_in_seconds = (<int64_t> days) * DAY_IN_SECONDS
cdef int seconds = <int> (timestamp - days_in_seconds)
cdef int microseconds = <int> ((timestamp - days_in_seconds - seconds) * 1000000)
return DATETIME_EPOC + timedelta_new(days, seconds, microseconds)

View File

@@ -88,6 +88,23 @@ class TestDatetime(BaseCassEngTestCase):
dts = self.DatetimeTest.objects.filter(test_id=1).values_list('created_at')
assert dts[0][0] is None
def test_datetime_invalid(self):
dt_value= 'INVALID'
with self.assertRaises(TypeError):
self.DatetimeTest.objects.create(test_id=2, created_at=dt_value)
def test_datetime_timestamp(self):
dt_value = 1454520554
self.DatetimeTest.objects.create(test_id=2, created_at=dt_value)
dt2 = self.DatetimeTest.objects(test_id=2).first()
assert dt2.created_at == datetime.utcfromtimestamp(dt_value)
def test_datetime_large(self):
dt_value = datetime(2038, 12, 31, 10, 10, 10, 123000)
self.DatetimeTest.objects.create(test_id=2, created_at=dt_value)
dt2 = self.DatetimeTest.objects(test_id=2).first()
assert dt2.created_at == dt_value
class TestBoolDefault(BaseCassEngTestCase):
class BoolDefaultValueTest(Model):

View File

@@ -0,0 +1,29 @@
# Copyright 2013-2016 DataStax, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from tests.unit.cython.utils import cyimport, cythontest
utils_testhelper = cyimport('tests.unit.cython.utils_testhelper')
try:
import unittest2 as unittest
except ImportError:
import unittest # noqa
class UtilsTest(unittest.TestCase):
"""Test Cython Utils functions"""
@cythontest
def test_datetime_from_timestamp(self):
utils_testhelper.test_datetime_from_timestamp(self.assertEqual)

View File

@@ -0,0 +1,23 @@
# Copyright 2013-2016 DataStax, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime
from cassandra.cython_utils cimport datetime_from_timestamp
def test_datetime_from_timestamp(assert_equal):
assert_equal(datetime_from_timestamp(1454781157.123456), datetime.datetime(2016, 2, 6, 17, 52, 37, 123456))
# PYTHON-452
assert_equal(datetime_from_timestamp(2177403010.123456), datetime.datetime(2038, 12, 31, 10, 10, 10, 123456))

View File

@@ -36,6 +36,8 @@ class TimeUtilTest(unittest.TestCase):
self.assertEqual(util.datetime_from_timestamp(0.123456), datetime.datetime(1970, 1, 1, 0, 0, 0, 123456))
self.assertEqual(util.datetime_from_timestamp(2177403010.123456), datetime.datetime(2038, 12, 31, 10, 10, 10, 123456))
def test_times_from_uuid1(self):
node = uuid.getnode()
now = time.time()