Would you like all the benefits of v7 UUIDs with none of the hexadecimal? Do you wish ULIDs were lowercase and one character shorter? Boy do I have the made-up-just-now standard for you.
Note: Not to be confused with:
- UwuId, which produces values like
😳d😳,,afa,,d🤗;sa😳sdk😍ghf,ldjddlsa - uwuid, which produces values like
uwu owo uwu uwu owo owo owo owo uwu uwu owo owo owo uwu uwu uwu owo uwu owo owo owo owo uwu owo owo uwu owo owo owo uwu uwu owo rawr xd owo owo uwu uwu uwu uwu owo owo uwu owo owo uwu owo uwu uwu uwu rawr xd uwu owo uwu uwu uwu owo owo uwu uwu uwu owo owo uwu uwu uwu uwu rawr xd owo uwu owo owo owo uwu owo owo owo uwu uwu uwu uwu uwu uwu uwu rawr xd owo uwu uwu uwu owo uwu owo owo uwu uwu owo owo owo owo owo uwu owo uwu owo owo owo uwu uwu owo uwu uwu uwu owo owo uwu uwu uwu owo uwu owo uwu owo uwu uwu owo owo owo uwu uwu owo uwu uwu uwu - UwUID, which produces values like
UwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUwUUw - UUID, which produces values like
733f8c2e-120d-44c5-b2f0-60ca50a99f99
For clarity, this specification is spelled as if it were an initialism.
what
UWUID is defined as a conversion function from and to v7 UUIDs. That is, a v7 UUID can be converted to a UWUID and back with no loss in specificity.
To convert a v7 UUID to UWUID, encode the 48-bit unix_ts_ms, 12-bit rand_a, and 62-bit rand_b (see draft-ietf-uuidrev-rfc4122bis-01 § 5.7) into the following 125-bit value:
0 1 2
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| unix_ts_ms |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0| rand_a | rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| rand_b |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
using this Base32 alphabet1 (abcdefghjkmnpqrstuvwxy0123456789; note iloz are excluded to reduce confusion with 0, 1, and 2):
| Value | Encoding | Value | Encoding | Value | Encoding | Value | Encoding |
|---|---|---|---|---|---|---|---|
| 0 | a | 9 | k | 18 | v | 27 | 5 |
| 1 | b | 10 | m | 19 | w | 28 | 6 |
| 2 | c | 11 | n | 20 | x | 29 | 7 |
| 3 | d | 12 | p | 21 | y | 30 | 8 |
| 4 | e | 13 | q | 22 | 0 | 31 | 9 |
| 5 | f | 14 | r | 23 | 1 | ||
| 6 | g | 15 | s | 24 | 2 | ||
| 7 | h | 16 | t | 25 | 3 | ||
| 8 | j | 17 | u | 26 | 4 |
To convert a UWUID to a v7 UUID, reverse these steps.
As an example, the UUID 017f22e2-79b0-7cc3-98c4-dc0c0c07398f would convert to the 25-character string abs6ure8qt3t3uug6btgarrpsa.
why
idk i thought this up on the way home from the grocery store.
Converting UUIDs to UWUIDs before display can have some benefits to end users,[dubious, discuss] such as being shorter to type and easier to copy (none of this double-click-and-drag horseshit). Meanwhile, storing these IDs as UUIDs allows you to take advantage of all of the technology built on top of generating, storing, and retrieving them.
Anyway this was stupid. Bye!
addendum: some changes i would make if i were serious
I wrote an almost-complete implementation of this in Rust, which converts the UUID to a big-endian u128 and then does some masks and bitshifts, and then I poked at the LLVM IR output. It's pretty good, but I would make the following changes to this spec to make it a bit easier to work with:
- No padding before
unix_ts_ms, so you can memcpy that straight over from the UUID. (This loses the advantage of being able to just look at a specific encoded prefix of the output, which you can do with v7 UUIDs and ULIDs (first ten characters)). - 2 bits of padding between
rand_aandrand_b, equaling0b10, which matches the variant field of the UUID. This allows you to mask and shift all of the random bits once, instead of differently for each field. - Which would leave 1 bit of additional padding, either before
rand_aor afterrand_b. I'm not sure whether there's an advantage to one or the other. (Maybe0b1beforerand_a, so that you can include the last bit of the version field in the mask?)
Ultimately I decided against incorporating these changes because it would make the ASCII diagram above more painful to look at.
-
Listen, if Douglas Crockford gets to make his own Base32 alphabet, I get to make one too.
