Skip to content

Commit

Permalink
Replace datetime.utcfromtimestamp
Browse files Browse the repository at this point in the history
It is depricated and to be removed soon.
datetime.fromtimestamp either include timezone into datetime, which we
do not want, or offset datetime from utc.
So, in order to have same behavior we have to ship separate function
that provides same results as datetime.utcfromtimestamp
  • Loading branch information
dkropachev committed Jan 5, 2025
1 parent d62eb38 commit caaee9f
Show file tree
Hide file tree
Showing 7 changed files with 35 additions and 22 deletions.
6 changes: 3 additions & 3 deletions cassandra/cqlengine/columns.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@
# limitations under the License.

from copy import deepcopy, copy
from datetime import date, datetime, timedelta
from datetime import date, datetime, timedelta, timezone
import logging
from uuid import UUID as _UUID

from cassandra import util
from cassandra.cqltypes import SimpleDateType, _cqltypes, UserType
from cassandra.cqlengine import ValidationError
from cassandra.cqlengine.functions import get_total_seconds
from cassandra.util import Duration as _Duration
from cassandra.util import Duration as _Duration, utcfromtimestamp

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -551,7 +551,7 @@ def to_python(self, value):
elif isinstance(value, date):
return datetime(*(value.timetuple()[:6]))

return datetime.utcfromtimestamp(value)
return utcfromtimestamp(value)

def to_database(self, value):
value = super(DateTime, self).to_database(value)
Expand Down
4 changes: 2 additions & 2 deletions cassandra/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import warnings

from cassandra import ConsistencyLevel, OperationTimedOut
from cassandra.util import unix_time_from_uuid1, maybe_add_timeout_to_query
from cassandra.util import unix_time_from_uuid1, maybe_add_timeout_to_query, utcfromtimestamp
from cassandra.encoder import Encoder
import cassandra.encoder
from cassandra.policies import ColDesc
Expand Down Expand Up @@ -1100,7 +1100,7 @@ class TraceEvent(object):

def __init__(self, description, timeuuid, source, source_elapsed, thread_name):
self.description = description
self.datetime = datetime.fromtimestamp(unix_time_from_uuid1(timeuuid), tz=timezone.utc)
self.datetime = utcfromtimestamp(unix_time_from_uuid1(timeuuid))
self.source = source
if source_elapsed is not None:
self.source_elapsed = timedelta(microseconds=source_elapsed)
Expand Down
11 changes: 10 additions & 1 deletion cassandra/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,17 @@

from cassandra import DriverException


def utcfromtimestamp(timestamp):
"""
It replicates behavior of datetime.utcfromtimestamp
"""
dt = datetime.datetime.fromtimestamp(timestamp, datetime.timezone.utc)
return datetime.datetime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, fold=dt.fold)


DATETIME_EPOC = datetime.datetime(1970, 1, 1)
UTC_DATETIME_EPOC = datetime.datetime.utcfromtimestamp(0)
UTC_DATETIME_EPOC = utcfromtimestamp(0)

_nan = float('nan')

Expand Down
7 changes: 4 additions & 3 deletions tests/integration/cqlengine/columns/test_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import unittest

import sys
from datetime import datetime, timedelta, date, tzinfo, time
from datetime import datetime, timedelta, date, tzinfo, time, timezone
from decimal import Decimal as D
from uuid import uuid4, uuid1
from packaging.version import Version
Expand All @@ -30,6 +30,7 @@
from cassandra.cqlengine.models import Model, ValidationError
from cassandra.cqlengine.usertype import UserType
from cassandra import util
from cassandra.util import utcfromtimestamp

from tests.integration import PROTOCOL_VERSION, CASSANDRA_VERSION, greaterthanorequalcass30, greaterthanorequalcass3_11
from tests.integration.cqlengine.base import BaseCassEngTestCase
Expand Down Expand Up @@ -97,7 +98,7 @@ def test_datetime_timestamp(self):
dt_value = 1454520554
self.DatetimeTest.objects.create(test_id=5, created_at=dt_value)
dt2 = self.DatetimeTest.objects(test_id=5).first()
self.assertEqual(dt2.created_at, datetime.utcfromtimestamp(dt_value))
self.assertEqual(dt2.created_at, utcfromtimestamp(dt_value))

def test_datetime_large(self):
dt_value = datetime(2038, 12, 31, 10, 10, 10, 123000)
Expand Down Expand Up @@ -809,7 +810,7 @@ def test_conversion_specific_date(self):
assert isinstance(uuid, UUID)

ts = (uuid.time - 0x01b21dd213814000) / 1e7 # back to a timestamp
new_dt = datetime.utcfromtimestamp(ts)
new_dt = utcfromtimestamp(ts)

# checks that we created a UUID1 with the proper timestamp
assert new_dt == dt
Expand Down
8 changes: 4 additions & 4 deletions tests/integration/cqlengine/model/test_model_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from uuid import uuid4, UUID
import random
from datetime import datetime, date, time
from datetime import datetime, date, time, timezone
from decimal import Decimal
from operator import itemgetter

Expand All @@ -26,7 +26,7 @@
from cassandra.cqlengine.management import drop_table
from cassandra.cqlengine.models import Model
from cassandra.query import SimpleStatement
from cassandra.util import Date, Time, Duration
from cassandra.util import Date, Time, Duration, utcfromtimestamp
from cassandra.cqlengine.statements import SelectStatement, DeleteStatement, WhereClause
from cassandra.cqlengine.operators import EqualsOperator

Expand Down Expand Up @@ -200,13 +200,13 @@ class AllDatatypesModel(Model):

sync_table(AllDatatypesModel)

input = ['ascii', 2 ** 63 - 1, bytearray(b'hello world'), True, datetime.utcfromtimestamp(872835240),
input = ['ascii', 2 ** 63 - 1, bytearray(b'hello world'), True, utcfromtimestamp(872835240),
Decimal('12.3E+7'), 2.39, 3.4028234663852886e+38, '123.123.123.123', 2147483647, 'text',
UUID('FE2B4360-28C6-11E2-81C1-0800200C9A66'), UUID('067e6162-3b6f-4ae2-a171-2470b63dff00'),
int(str(2147483647) + '000')]

AllDatatypesModel.create(id=0, a='ascii', b=2 ** 63 - 1, c=bytearray(b'hello world'), d=True,
e=datetime.utcfromtimestamp(872835240), f=Decimal('12.3E+7'), g=2.39,
e=utcfromtimestamp(872835240), f=Decimal('12.3E+7'), g=2.39,
h=3.4028234663852886e+38, i='123.123.123.123', j=2147483647, k='text',
l=UUID('FE2B4360-28C6-11E2-81C1-0800200C9A66'),
m=UUID('067e6162-3b6f-4ae2-a171-2470b63dff00'), n=int(str(2147483647) + '000'),
Expand Down
6 changes: 3 additions & 3 deletions tests/integration/cqlengine/model/test_udts.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.
import unittest

from datetime import datetime, date, time
from datetime import datetime, date, time, timezone
from decimal import Decimal
from mock import Mock
from uuid import UUID, uuid4
Expand All @@ -23,7 +23,7 @@
from cassandra.cqlengine import columns, connection
from cassandra.cqlengine.management import sync_table, drop_table, sync_type, create_keyspace_simple, drop_keyspace
from cassandra.cqlengine import ValidationError
from cassandra.util import Date, Time
from cassandra.util import Date, Time, utcfromtimestamp

from tests.integration import PROTOCOL_VERSION
from tests.integration.cqlengine.base import BaseCassEngTestCase
Expand Down Expand Up @@ -272,7 +272,7 @@ def test_can_insert_udts_with_all_datatypes(self):
self.addCleanup(drop_table, AllDatatypesModel)

input = AllDatatypes(a='ascii', b=2 ** 63 - 1, c=bytearray(b'hello world'), d=True,
e=datetime.utcfromtimestamp(872835240), f=Decimal('12.3E+7'), g=2.39,
e=utcfromtimestamp(872835240), f=Decimal('12.3E+7'), g=2.39,
h=3.4028234663852886e+38, i='123.123.123.123', j=2147483647, k='text',
l=UUID('FE2B4360-28C6-11E2-81C1-0800200C9A66'),
m=UUID('067e6162-3b6f-4ae2-a171-2470b63dff00'), n=int(str(2147483647) + '000'))
Expand Down
15 changes: 9 additions & 6 deletions tests/unit/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
import tempfile
import time
from binascii import unhexlify
from datetime import tzinfo

from dateutil.tz import tzlocal

import cassandra
from cassandra import util
Expand All @@ -41,7 +44,7 @@
from cassandra.util import (
OPEN_BOUND, Date, DateRange, DateRangeBound,
DateRangePrecision, Time, ms_timestamp_from_datetime,
datetime_from_timestamp
datetime_from_timestamp, utcfromtimestamp
)
from tests.unit.util import check_sequence_consistency

Expand Down Expand Up @@ -200,7 +203,7 @@ def test_empty_value(self):

def test_datetype(self):
now_time_seconds = time.time()
now_datetime = datetime.datetime.utcfromtimestamp(now_time_seconds)
now_datetime = utcfromtimestamp(now_time_seconds)

# Cassandra timestamps in millis
now_timestamp = now_time_seconds * 1e3
Expand All @@ -211,7 +214,7 @@ def test_datetype(self):
# deserialize
# epoc
expected = 0
self.assertEqual(DateType.deserialize(int64_pack(1000 * expected), 0), datetime.datetime.utcfromtimestamp(expected))
self.assertEqual(DateType.deserialize(int64_pack(1000 * expected), 0), utcfromtimestamp(expected))

# beyond 32b
expected = 2 ** 33
Expand Down Expand Up @@ -738,7 +741,7 @@ def get_upper_bound(seconds):
The way to do this is to add one month and leave the date at YEAR-MONTH-01 00:00:00 000000.
Then substract one millisecond.
"""
dt = datetime.datetime.fromtimestamp(seconds / 1000.0, tz=utc_timezone)
dt = utcfromtimestamp(seconds / 1000.0)
dt = dt + datetime.timedelta(days=32)
dt = dt.replace(day=1) - datetime.timedelta(microseconds=1)
return int((dt - self.epoch).total_seconds() * 1000)
Expand All @@ -765,7 +768,7 @@ def get_upper_bound(seconds):
The way to do this is to add one year and leave the date at YEAR-01-01 00:00:00 000000.
Then substract one millisecond.
"""
dt = datetime.datetime.fromtimestamp(seconds / 1000.0, tz=utc_timezone)
dt = utcfromtimestamp(seconds / 1000.0)
dt = dt + datetime.timedelta(days=370)
dt = dt.replace(day=1) - datetime.timedelta(microseconds=1)

Expand Down Expand Up @@ -812,7 +815,7 @@ def truncate_date(number):
For example if truncate_kwargs = {"hour": 0, "minute": 0, "second": 0, "microsecond": 0} the returned
value will be the original given date but with the hours, minutes, seconds and microseconds set to 0
"""
dt = datetime.datetime.fromtimestamp(number / 1000.0, tz=utc_timezone)
dt = utcfromtimestamp(number / 1000.0)
dt = dt.replace(**truncate_kwargs)
return round((dt - self.epoch).total_seconds() * 1000.0)

Expand Down

0 comments on commit caaee9f

Please sign in to comment.