开发者

UUID1 from UTC Timestamp in Python?

The problem goes like this:

My application is deployed on a remote server with different timezo开发者_StackOverflowne and I want to generate a uuid1 against UTC timestamp. I can't find a way to generate uuid1 from any given timestamp. The reason I want to do this is that I don't want to get into the hassle of calculating my local time where my local time does not observe Daylight saving time and the remote server does and a result the presentation logic becomes cumbersome.

The limitation is that the Timestamp needs to be stored as uuid1. Any idea or workaround for this will be higly appreciated.


the UUID class will do the bit-juggling if you give it the right fragments - http://docs.python.org/library/uuid.html

to get the right components you can copy the the uuid1 code from python2.7:

def uuid1(node=None, clock_seq=None):
        """Generate a UUID from a host ID, sequence number, and the current time.
        If 'node' is not given, getnode() is used to obtain the hardware
        address.  If 'clock_seq' is given, it is used as the sequence number;
        otherwise a random 14-bit sequence number is chosen."""
    # When the system provides a version-1 UUID generator, use it (but don't
    # use UuidCreate here because its UUIDs don't conform to RFC 4122).
    if _uuid_generate_time and node is clock_seq is None:
        _buffer = ctypes.create_string_buffer(16)
        _uuid_generate_time(_buffer)
        return UUID(bytes=_buffer.raw)
    global _last_timestamp
    import time
    nanoseconds = int(time.time() * 1e9)
    # 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.
    timestamp = int(nanoseconds//100) + 0x01b21dd213814000L
    if _last_timestamp is not None and timestamp <= _last_timestamp:
        timestamp = _last_timestamp + 1
    _last_timestamp = timestamp
    if clock_seq is None:
        import random
        clock_seq = random.randrange(1<<14L) # instead of stable storage
    time_low = timestamp & 0xffffffffL
    time_mid = (timestamp >> 32L) & 0xffffL
    time_hi_version = (timestamp >> 48L) & 0x0fffL
    clock_seq_low = clock_seq & 0xffL
    clock_seq_hi_variant = (clock_seq >> 8L) & 0x3fL
    if node is None:
        node = getnode()
    return UUID(fields=(time_low, time_mid, time_hi_version,
                        clock_seq_hi_variant, clock_seq_low, node), version=1)

all you need to do is copy+paste that and modify the timestamp part to use a fixed value (you can ignore the last_timestamp part if you know that your times are distinct - that is just to avoid duplicates when the clock resolution is insufficient).


Here is a function to extract a Unix timestamp from a UUID v1:

def uuid1_unix_timestamp(uuid_):
    '''
    Extract timestamp from UUID1.

    Params
    ------
    uuid_ : uuid.UUID
        UUID v1 instance.

    Returns
    -------
    float
        Unix timestamp.
    '''
    import datetime as dt

    # UUID v1 timestamp is measured from [00:00:00, 1 October 1582][1].
    #
    # [1]: https://quora.com/Why-UUID-v1-timestamp-measured-from-00-00-00-00-15-October-
    return (uuid_.time * 1e-7 - (dt.datetime.utcfromtimestamp(0) -
                                 dt.datetime(1582, 10, 15)).total_seconds())

Usage:

>>> import datetime as dt
>>> # Extract timestamp from a new Python UUID v1 instance.
>>> uuid1_unix_timestamp(uuid.uuid1())
1533834175.8219986
>>> # Convert timestamp from Python UUID v1 to Python datetime.
>>> timestamp = uuid1_unix_timestamp(uuid.uuid1())
>>> dt.datetime.utcfromtimestamp(timestamp)
datetime.datetime(2018, 8, 9, 17, 3, 10, 122999)
>>> # Extract timestamp from a UUID v1 string.
>>> uuid_ = uuid.UUID('4101d7a1-9bf6-11e8-b86d-9cb6d0e37eb4')
>>> uuid1_unix_timestamp(uuid_)
1533834258.9699993


The Cassandra driver for Python now has a function for this very purpose:

cassandra.util.uuid_from_time()

https://datastax.github.io/python-driver/api/cassandra/util.html#cassandra.util.uuid_from_time


Here is a sample code that will generate a UUID1 from a given integer timestamp

Note that while timestamp part will stay static, a part of the uuid is still random. You can pass the clock_seq value if you want the uuid to stay the same

import uuid

try:
    import unittest.mock as mock
except ImportError:
    import mock


def fixed_uuid1(timestamp, *args, **kwargs):
    """Returns a UUID1 from a fixed timestamp"""
    with mock.patch('uuid._uuid_generate_time', None), \
            mock.patch('uuid._last_timestamp', None), \
            mock.patch('time.time', return_value=timestamp):
        return uuid.uuid1(*args, **kwargs)


print(fixed_uuid1(0))
print(fixed_uuid1(0, clock_seq=0))
print(fixed_uuid1(1565627822.303553))
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜