Do uuid.uuid1 values sort in creation order, and what does uuid.uuid7 change?
answer
- Which field lands in front
- The fastest-changing bits print first
- A wrap every seven minutes or so
- UUID.time reassembles the reading
- 3.14 added a millisecond-first version
basics
~20 sNo. A version 1 UUID puts the low 32 bits of its timestamp first, so text and byte order do not track time. Sort by UUID.time instead, or use uuid.uuid7(), added in Python 3.14, whose leading bytes are a millisecond timestamp.
solid answer
~40 s`uuid.uuid1()` encodes a 60-bit clock reading, but the layout writes `time_low` — the *least* significant 32 bits — into the first four bytes, then the middle and high parts. Those low bits wrap roughly every seven minutes, so comparing two version 1 UUIDs as strings or as bytes tells you nothing about which was made first. What you can do is read `UUID.time`, which reassembles the full 60-bit value from the three fields, and sort on that integer. Python 3.14 added `uuid.uuid6`, `uuid.uuid7` and `uuid.uuid8`: `uuid7()` writes a 48-bit big-endian Unix millisecond timestamp into the leading bytes followed by a counter and random bits, so its values increase monotonically and their natural byte and text ordering does match creation order.
code
python · 7 linesimport uuid
u = uuid.uuid1()
print(u.version, u.node == uuid.getnode())
print(str(u)[:8] == format(u.time_low, "08x"))
older, newer = uuid.uuid7(), uuid.uuid7()
print(newer.version, str(newer) > str(older))go deeper
Remember the headline: version 1 UUIDs contain a timestamp but do not sort by it, and Python 3.14 added uuid.uuid7() whose values do sort. If you need creation order, store a timestamp column.
Explain the layout — time_low first, wrapping about every seven minutes — and that UUID.time recombines the fields. Name uuid.uuid6, uuid.uuid7 and uuid.uuid8 as 3.14 additions and say what version 7 puts in its leading bytes.
Weigh what an identifier discloses: version 7 dates every record to the millisecond and version 1 can expose a host fingerprint, against the convenience of an ordered id. Say when a plain timestamp column is the better answer.
Decide the standard your systems generate, knowing that migrating an identifier version is a data-wide change, and that ordering coupled to an id's byte layout is a constraint every future consumer inherits.
This question separates people who have read a UUID's layout from people who have only used one. The intuition that a time-based identifier must sort by time is reasonable and, for version 1, simply false. ### What version 1 actually writes A `uuid.uuid1()` value carries a 60-bit timestamp counting 100-nanosecond intervals since 1582-10-15, a 14-bit clock sequence, and a 48-bit node id from `uuid.getnode()`. The layout, inherited from the original specification, stores those timestamp bits in three separate fields in a surprising order: `time_low` (the lowest 32 bits) comes *first*, then `time_mid`, then the high bits packed alongside the version nibble. So the first eight characters of the printed form — and the first four bytes of `u.bytes` — are the fastest-changing part of the clock. Thirty-two bits of 100-nanosecond ticks is about 429.5 seconds, a little over seven minutes. Every seven minutes that leading field wraps back to zero and starts climbing again. Two values a minute apart may compare in either direction; two values a day apart are effectively random with respect to each other. Lexicographic comparison of the text, byte comparison of `u.bytes`, and comparison of `u.int` all inherit the same problem, because they all read the fields in stored order. The information is not lost, only scattered. `UUID.time` recombines the three fields into the full 60-bit integer, so `sorted(ids, key=lambda u: u.time)` does order version 1 values by creation instant, subject to clock resolution and to the assumption that the generating clocks agree. `UUID.node`, `UUID.clock_seq` and `UUID.fields` expose the rest. ### What Python 3.14 added Python 3.14 grew three new generators: `uuid.uuid6()`, `uuid.uuid7()` and `uuid.uuid8()`, alongside the `uuid.NIL` and `uuid.MAX` constants. * `uuid.uuid6()` is version 1's data with the timestamp fields rearranged into most-significant-first order, so the value sorts by time. It exists mainly as a drop-in for systems that already generate version 1 values. * `uuid.uuid7()` is the one to reach for. Its leading 48 bits are a big-endian Unix timestamp in **milliseconds**, followed by version and variant bits, a counter, and random bits. Successive calls produce monotonically increasing values, so ordinary byte order, text order and integer order all agree with creation order — and `UUID.time` on such a value gives back that millisecond timestamp rather than a 1582-based tick count. * `uuid.uuid8()` takes three integers and lets you define your own layout inside the version 8 envelope; it is an escape hatch, not a default. ```python import uuid u = uuid.uuid1() print(str(u)[:8] == format(u.time_low, "08x")) older, newer = uuid.uuid7(), uuid.uuid7() print(newer.version, str(newer) > str(older)) ``` The first line confirms that the printed prefix is the low timestamp field. The last prints `7 True` — the newer version 7 value sorts after the older one as plain text. ### The judgement to carry away Time-ordered identifiers are not free. A version 7 value publishes its creation millisecond to anyone holding it, which is information you may not want to hand out; a version 4 value publishes nothing. A version 1 value publishes both a timestamp and, when `uuid.getnode()` found real hardware, a stable machine fingerprint — which is the usual reason to avoid it in anything customer-facing. And if all you need is "which of these rows came first", a stored creation timestamp answers the question directly, with a resolution and a timezone you control, and without coupling ordering to an identifier's byte layout. Choosing `uuid7` because the ordering genuinely buys something is sound engineering; choosing it because ordered identifiers feel tidier is not.
- How would you sort a list of version 1 UUIDs into creation order today?Sort on the `UUID.time` attribute, which recombines `time_low`, `time_mid` and the high bits into the full 60-bit reading: `sorted(ids, key=lambda u: u.time)`. Sorting the objects themselves, or their text, orders by the stored field layout and therefore by the low timestamp bits. Bear in mind the values came from possibly-different clocks, so the ordering is only as trustworthy as those clocks agree.
- What does a version 7 UUID reveal to whoever holds it?Its creation time to the millisecond, because the leading 48 bits are a Unix millisecond timestamp in plain big-endian order — no parsing tricks needed. That is often harmless internally and unwelcome on a public identifier, since it dates every record and lets an observer measure your creation rate. A version 4 value leaks nothing by comparison, which is the trade you are making.
saying these in an interview costs you the question
- Assumes any time-based UUID sorts chronologically as text
- Believes uuid1 is unusable because its timestamp is lost
- Claims uuid7 exists in Python 3.13 or earlier
- Reads only the first field and calls it the timestamp
- Thinks a sortable identifier reveals nothing about creation time