如何在Python中从UTC时间戳生成UUID1?

4 投票
4 回答
4398 浏览
提问于 2025-04-17 00:08

问题是这样的:

我的应用程序部署在一个远程服务器上,这个服务器的时区和我本地的不一样。我想根据UTC时间戳生成一个uuid1,但我找不到从任何给定时间戳生成uuid1的方法。我之所以想这样做,是因为我不想麻烦地去计算我本地的时间,特别是因为我的本地时间不遵循夏令时,而远程服务器却遵循,这样一来,处理逻辑就变得很复杂。

限制是时间戳需要以uuid1的形式存储。如果有人有任何想法或解决办法,我将非常感激。

4 个回答

2

这里有一个函数,可以从UUID v1中提取出Unix时间戳:

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())

用法:

>>> 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
3

现在,Python的Cassandra驱动程序有一个专门用来实现这个功能的函数:

cassandra.util.uuid_from_time()

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

4

UUID类会处理一些复杂的位运算,只要你给它正确的部分就行 - http://docs.python.org/library/uuid.html

要获取正确的组件,你可以从Python 2.7中复制uuid1的代码:

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)

你只需要复制粘贴这段代码,然后把时间戳的部分改成一个固定的值(如果你知道你的时间是不同的,可以忽略最后的时间戳部分 - 这个部分主要是为了避免在时钟精度不足时出现重复的UUID)。

撰写回答