Collect time functions in util, add uuid_from_time and min/max functions
PYTHON-99 Conflicts: cassandra/cqltypes.py cassandra/util.py
This commit is contained in:
@@ -34,24 +34,27 @@ from collections import namedtuple
|
||||
import datetime
|
||||
from decimal import Decimal
|
||||
import io
|
||||
import logging
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
import sys
|
||||
from uuid import UUID
|
||||
|
||||
import six
|
||||
from six.moves import range
|
||||
import sys
|
||||
from uuid import UUID
|
||||
import warnings
|
||||
|
||||
|
||||
from cassandra.marshal import (int8_pack, int8_unpack,
|
||||
uint16_pack, uint16_unpack, uint32_pack, uint32_unpack,
|
||||
int32_pack, int32_unpack, int64_pack, int64_unpack,
|
||||
float_pack, float_unpack, double_pack, double_unpack,
|
||||
varint_pack, varint_unpack)
|
||||
from cassandra.util import OrderedMap, sortedset, Time
|
||||
from cassandra import util
|
||||
|
||||
apache_cassandra_type_prefix = 'org.apache.cassandra.db.marshal.'
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
if six.PY3:
|
||||
_number_types = frozenset((int, float))
|
||||
@@ -72,16 +75,17 @@ def trim_if_startswith(s, prefix):
|
||||
|
||||
|
||||
def unix_time_from_uuid1(u):
|
||||
return (u.time - 0x01B21DD213814000) / 10000000.0
|
||||
|
||||
|
||||
DATETIME_EPOC = datetime.datetime(1970, 1, 1)
|
||||
msg = "'cassandra.cqltypes.unix_time_from_uuid1' has moved to 'cassandra.util'. This entry point will be removed in the next major version."
|
||||
warnings.warn(msg, DeprecationWarning)
|
||||
log.warn(msg)
|
||||
return util.unix_time_from_uuid1(u)
|
||||
|
||||
|
||||
def datetime_from_timestamp(timestamp):
|
||||
# PYTHON-119: workaround for Windows
|
||||
dt = DATETIME_EPOC + datetime.timedelta(seconds=timestamp)
|
||||
return dt
|
||||
msg = "'cassandra.cqltypes.datetime_from_timestamp' has moved to 'cassandra.util'. This entry point will be removed in the next major version."
|
||||
warnings.warn(msg, DeprecationWarning)
|
||||
log.warn(msg)
|
||||
return util.datetime_from_timestamp(timestamp)
|
||||
|
||||
|
||||
_casstypes = {}
|
||||
@@ -581,7 +585,7 @@ class DateType(_CassandraType):
|
||||
@staticmethod
|
||||
def deserialize(byts, protocol_version):
|
||||
timestamp = int64_unpack(byts) / 1000.0
|
||||
return datetime_from_timestamp(timestamp)
|
||||
return util.datetime_from_timestamp(timestamp)
|
||||
|
||||
@staticmethod
|
||||
def serialize(v, protocol_version):
|
||||
@@ -652,7 +656,7 @@ class SimpleDateType(_CassandraType):
|
||||
@staticmethod
|
||||
def deserialize(byts, protocol_version):
|
||||
timestamp = SimpleDateType.seconds_per_day * (uint32_unpack(byts) - 2 ** 31)
|
||||
dt = datetime_from_timestamp(timestamp)
|
||||
dt = util.datetime_from_timestamp(timestamp)
|
||||
return datetime.date(dt.year, dt.month, dt.day)
|
||||
|
||||
|
||||
@@ -661,8 +665,8 @@ class TimeType(_CassandraType):
|
||||
|
||||
@classmethod
|
||||
def validate(cls, val):
|
||||
if not isinstance(val, Time):
|
||||
val = Time(val)
|
||||
if not isinstance(val, util.Time):
|
||||
val = util.Time(val)
|
||||
return val
|
||||
|
||||
@staticmethod
|
||||
@@ -670,12 +674,12 @@ class TimeType(_CassandraType):
|
||||
try:
|
||||
nano = val.nanosecond_time
|
||||
except AttributeError:
|
||||
nano = Time(val).nanosecond_time
|
||||
nano = util.Time(val).nanosecond_time
|
||||
return int64_pack(nano)
|
||||
|
||||
@staticmethod
|
||||
def deserialize(byts, protocol_version):
|
||||
return Time(int64_unpack(byts))
|
||||
return util.Time(int64_unpack(byts))
|
||||
|
||||
|
||||
class UTF8Type(_CassandraType):
|
||||
@@ -771,7 +775,7 @@ class ListType(_SimpleParameterizedType):
|
||||
class SetType(_SimpleParameterizedType):
|
||||
typename = 'set'
|
||||
num_subtypes = 1
|
||||
adapter = sortedset
|
||||
adapter = util.sortedset
|
||||
|
||||
|
||||
class MapType(_ParameterizedType):
|
||||
@@ -794,7 +798,7 @@ class MapType(_ParameterizedType):
|
||||
length = 2
|
||||
numelements = unpack(byts[:length])
|
||||
p = length
|
||||
themap = OrderedMap()
|
||||
themap = util.OrderedMap()
|
||||
for _ in range(numelements):
|
||||
key_len = unpack(byts[p:p + length])
|
||||
p += length
|
||||
|
||||
@@ -1,4 +1,128 @@
|
||||
from __future__ import with_statement
|
||||
import calendar
|
||||
import datetime
|
||||
import random
|
||||
import six
|
||||
import uuid
|
||||
|
||||
DATETIME_EPOC = datetime.datetime(1970, 1, 1)
|
||||
|
||||
|
||||
def datetime_from_timestamp(timestamp):
|
||||
"""
|
||||
Creates a timezone-agnostic datetime from timestamp (in seconds) in a consistent manner.
|
||||
Works around a Windows issue with large negative timestamps (PYTHON-119),
|
||||
and rounding differences in Python 3.4 (PYTHON-340).
|
||||
|
||||
:param timestamp: a unix timestamp, in seconds
|
||||
|
||||
:rtype: datetime
|
||||
"""
|
||||
dt = DATETIME_EPOC + datetime.timedelta(seconds=timestamp)
|
||||
return dt
|
||||
|
||||
|
||||
def unix_time_from_uuid1(uuid_arg):
|
||||
"""
|
||||
Converts a version 1 :class:`uuid.UUID` to a timestamp with the same precision
|
||||
as :meth:`time.time()` returns. This is useful for examining the
|
||||
results of queries returning a v1 :class:`~uuid.UUID`.
|
||||
|
||||
:param uuid_arg: a version 1 :class:`~uuid.UUID`
|
||||
|
||||
:rtype: timestamp
|
||||
|
||||
"""
|
||||
return (uuid_arg.time - 0x01B21DD213814000) / 10000000.0
|
||||
|
||||
|
||||
def datetime_from_uuid1(uuid_arg):
|
||||
"""
|
||||
Creates a timezone-agnostic datetime from the timestamp in the
|
||||
specified type-1 UUID.
|
||||
|
||||
:param uuid_arg: a version 1 :class:`~uuid.UUID`
|
||||
|
||||
:rtype: timestamp
|
||||
|
||||
"""
|
||||
return datetime_from_timestamp(unix_time_from_uuid1(uuid_arg))
|
||||
|
||||
|
||||
def min_uuid_from_time(timestamp):
|
||||
"""
|
||||
Generates the minimum TimeUUID (type 1) for a given timestamp, as compared by Cassandra.
|
||||
|
||||
See :func:`uuid_from_time` for argument and return types.
|
||||
"""
|
||||
return uuid_from_time(timestamp, 0x80, 0x808080808080) # Cassandra does byte-wise comparison; fill with min signed bytes (0x80 = -128)
|
||||
|
||||
|
||||
def max_uuid_from_time(timestamp):
|
||||
"""
|
||||
Generates the maximum TimeUUID (type 1) for a given timestamp, as compared by Cassandra.
|
||||
|
||||
See :func:`uuid_from_time` for argument and return types.
|
||||
"""
|
||||
return uuid_from_time(timestamp, 0x3f7f, 0x7f7f7f7f7f7f) # Max signed bytes (0x7f = 127)
|
||||
|
||||
|
||||
def uuid_from_time(time_arg, clock_seq=None, node=None):
|
||||
"""
|
||||
Converts a datetime or timestamp to a type 1 :class:`uuid.UUID`.
|
||||
|
||||
:param time_arg:
|
||||
The time to use for the timestamp portion of the UUID.
|
||||
This can either be a :class:`datetime` object or a timestamp
|
||||
in seconds (as returned from :meth:`time.time()`).
|
||||
:type datetime: :class:`datetime` or timestamp
|
||||
|
||||
:param clock_seq:
|
||||
Clock sequence field for the UUID (up to 14 bits). If not specified,
|
||||
a random sequence is generated.
|
||||
:type clock_seq: int
|
||||
|
||||
:param node:
|
||||
None integer for the UUID (up to 48 bits). If not specified, this
|
||||
field is randomized.
|
||||
:type node: long
|
||||
|
||||
:rtype: :class:`uuid.UUID`
|
||||
|
||||
"""
|
||||
if hasattr(time_arg, 'utctimetuple'):
|
||||
seconds = int(calendar.timegm(time_arg.utctimetuple()))
|
||||
microseconds = (seconds * 1e6) + time_arg.time().microsecond
|
||||
else:
|
||||
microseconds = int(time_arg * 1e6)
|
||||
|
||||
# 0x01b21dd213814000 is the number of 100-ns intervals between the
|
||||
# UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
|
||||
intervals = int(microseconds * 10) + 0x01b21dd213814000
|
||||
|
||||
time_low = intervals & 0xffffffff
|
||||
time_mid = (intervals >> 32) & 0xffff
|
||||
time_hi_version = (intervals >> 48) & 0x0fff
|
||||
|
||||
if clock_seq is None:
|
||||
clock_seq = random.getrandbits(14)
|
||||
|
||||
clock_seq_low = clock_seq & 0xff
|
||||
clock_seq_hi_variant = 0x80 | ((clock_seq >> 8) & 0x3f)
|
||||
|
||||
if node is None:
|
||||
node = random.getrandbits(48)
|
||||
node &= 0xffffffffff
|
||||
|
||||
return uuid.UUID(fields=(time_low, time_mid, time_hi_version,
|
||||
clock_seq_hi_variant, clock_seq_low, node), version=1)
|
||||
|
||||
LOWEST_TIME_UUID = uuid.UUID('00000000-0000-1000-8080-808080808080')
|
||||
""" The lowest possible TimeUUID, as sorted by Cassandra. """
|
||||
|
||||
HIGHEST_TIME_UUID = uuid.UUID('ffffffff-ffff-1fff-bf7f-7f7f7f7f7f7f')
|
||||
""" The highest possible TimeUUID, as sorted by Cassandra. """
|
||||
|
||||
|
||||
try:
|
||||
from collections import OrderedDict
|
||||
@@ -557,7 +681,6 @@ except ImportError:
|
||||
return isect
|
||||
|
||||
from collections import Mapping
|
||||
import six
|
||||
from six.moves import cPickle
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user