Generate a UUID from a Unix timestamp in milliseconds and random bits. UUIDv7 objects feature monotonicity within a millisecond.
()
| 843 | |
| 844 | |
| 845 | def uuid7(): |
| 846 | """Generate a UUID from a Unix timestamp in milliseconds and random bits. |
| 847 | |
| 848 | UUIDv7 objects feature monotonicity within a millisecond. |
| 849 | """ |
| 850 | # --- 48 --- -- 4 -- --- 12 --- -- 2 -- --- 30 --- - 32 - |
| 851 | # unix_ts_ms | version | counter_hi | variant | counter_lo | random |
| 852 | # |
| 853 | # 'counter = counter_hi | counter_lo' is a 42-bit counter constructed |
| 854 | # with Method 1 of RFC 9562, §6.2, and its MSB is set to 0. |
| 855 | # |
| 856 | # 'random' is a 32-bit random value regenerated for every new UUID. |
| 857 | # |
| 858 | # If multiple UUIDs are generated within the same millisecond, the LSB |
| 859 | # of 'counter' is incremented by 1. When overflowing, the timestamp is |
| 860 | # advanced and the counter is reset to a random 42-bit integer with MSB |
| 861 | # set to 0. |
| 862 | |
| 863 | global _last_timestamp_v7 |
| 864 | global _last_counter_v7 |
| 865 | |
| 866 | nanoseconds = time.time_ns() |
| 867 | timestamp_ms = nanoseconds // 1_000_000 |
| 868 | |
| 869 | if _last_timestamp_v7 is None or timestamp_ms > _last_timestamp_v7: |
| 870 | counter, tail = _uuid7_get_counter_and_tail() |
| 871 | else: |
| 872 | if timestamp_ms < _last_timestamp_v7: |
| 873 | timestamp_ms = _last_timestamp_v7 + 1 |
| 874 | # advance the 42-bit counter |
| 875 | counter = _last_counter_v7 + 1 |
| 876 | if counter > 0x3ff_ffff_ffff: |
| 877 | # advance the 48-bit timestamp |
| 878 | timestamp_ms += 1 |
| 879 | counter, tail = _uuid7_get_counter_and_tail() |
| 880 | else: |
| 881 | # 32-bit random data |
| 882 | tail = int.from_bytes(os.urandom(4)) |
| 883 | |
| 884 | unix_ts_ms = timestamp_ms & 0xffff_ffff_ffff |
| 885 | counter_msbs = counter >> 30 |
| 886 | # keep 12 counter's MSBs and clear variant bits |
| 887 | counter_hi = counter_msbs & 0x0fff |
| 888 | # keep 30 counter's LSBs and clear version bits |
| 889 | counter_lo = counter & 0x3fff_ffff |
| 890 | # ensure that the tail is always a 32-bit integer (by construction, |
| 891 | # it is already the case, but future interfaces may allow the user |
| 892 | # to specify the random tail) |
| 893 | tail &= 0xffff_ffff |
| 894 | |
| 895 | int_uuid_7 = unix_ts_ms << 80 |
| 896 | int_uuid_7 |= counter_hi << 64 |
| 897 | int_uuid_7 |= counter_lo << 32 |
| 898 | int_uuid_7 |= tail |
| 899 | # by construction, the variant and version bits are already cleared |
| 900 | int_uuid_7 |= _RFC_4122_VERSION_7_FLAGS |
| 901 | res = UUID._from_int(int_uuid_7) |
| 902 |
nothing calls this directly
no test coverage detected
searching dependent graphs…