Skip to content
This repository was archived by the owner on Jul 9, 2024. It is now read-only.
This repository was archived by the owner on Jul 9, 2024. It is now read-only.

Discussion: UUIDv7 subsecond precision encoding #24

@kyzer-davis

Description

@kyzer-davis

Question: Factions of a second representation or specific number of milliseconds/microseconds/nanoseconds for subsecond precision encoding within UUIDv7's subsec_a, subsec_b, and subsec_seq_node

Current draft-02 Implementation as per @bradleypeabody (who wrote the UUIDv7 section)

  • UUIDv7 encodes subsecond precision as fraction of a second:
  • Nanoseconds (ns) encoding utilizes 38 total bits
  • Microsecond (µs) encoding utilizes 24 total bits
  • Millisecond (ms) encoding utilizes 12 total bits

Sources from email between Brad and I on the topic:

[UUIDv7] supposed to be a fraction as opposed to the specific number of milliseconds.
If you want to indicate .75 seconds (three quarters of a second), you would write in decimal, following the period, the digits "75", right?
Well you do the exact same thing in binary, except that instead of "7" meaning 7 tenths, plus "5" meaning 5 hundredths, you do:
11
which means 1 half, plus one quarter.
Or, put another way, in decimal the digits go, from left to right:
tenths
hundredths
thousandths
ten thousandths
etc.
In binary it goes
halfs
quarters
eights
sixteeths
etc

To encode a fraction of a second s (expressed as a rational number in the range [0-1), e.g. 0.321 seconds) into a bit field of length n, calculate m as the maximum integer value representable with n bits plus one (aka 2^n, 1<<n, or "an int with the lower n bits set to 1, converted to a float64"). And then the formula is simply: s / (1/m) - the remaining fractional part is truncated and the number encoded as an integer. (e.g. 0.321 seconds encoded with 12 bits would be 0.321 divided by (1/4096) = 1314.816, truncated and expressed an integer value gives 1314 or in hex 0x522 or in binary 010100100010)

Taking a page from how floating point numbers are encoded, we could express fractions of a second as a bitfield divisor of whatever length a particular implementation uses. E.g. JS implementations which only have millisecond precision can reliably encode this information into 12 bits (probably 10 or 11 actually, but I digress). The first bit set to 1 would mean 0.5 seconds, two bits set to 1 and 1 would mean .75 seconds, a 0 and then 1 would be 0.25 seconds, etc.

One down side I see is that it requires floating point math (or some system that can represent fractional numbers) for encoding and decoding, which perhaps on some embedded systems may not necessarily be readily available - not sure how big a deal that concern is. It's also slightly more complicated than dealing with integer math, but I don't think to an extent that is problematic.


Alternative is specific number of milliseconds/microseconds/nanoseconds as integer.

  • Nanoseconds (ns) in a timestamp take 30 bits. (1,000,000,000 nanoseconds in 1 seconds so 1000000000 = 111011100110101100101000000000)
  • Microseconds (µs) in a timestamp take 20 bits. (1,000,000 microseconds in 1 second so 1000000 = 11110100001001000000)
  • Milliseconds (ms) in a timestamp take 10 bits. (1,000 millisecond in 1 second so 1000 = 1111101000)

Sources: https://en.wikipedia.org/wiki/Orders_of_magnitude_(time)

More Discussion on the alternative:

If alternative was utilized in Draft 02 we would encode as such:

  • Milliseconds (ms): All 12 bits of subsec_a is fully dedicated to millisecond information with a pad of two bits at the start since we only need 10. Easier to do this padding since Version bits come up right after.
  • Microseconds (µs): All 24 bits of both subsec_a and subsec_b utilized for microsecond information with 4 bits padded at the start since we only require 20. Easier to pad here because Variant bits are coming up.
  • Nanoseconds (ns): subsec_a, subsec_b , and 6 bits of subsec_seq_nod used for nanosecond information. Final 48 bits of subsec_seq_nod are used for random/entropy/node data. No padding required for this scenario.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DiscussionFurther information is requestedOut of ScopeTopics not in scope for the RFC/Draft

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions