Skip to content

1.7. UUIDv7

Fabio Lima edited this page Feb 16, 2024 · 3 revisions

Time-ordered UUID with Unix Epoch

This is an implementation of UUID v7.

This library provides 3 types:

  • Type 1 (default):
    • Time: 48 bits.
    • Counter: 26 bits (incremented by 1).
    • Random: 48 bits (always randomized).
  • Type 2 (plus 1):
    • Time: 48 bits.
    • Monotonic random: 74 bits (incremented by 1).
  • Type 3 (plus n):
    • Time: 48 bits.
    • Monotonic random: 74 bits (incremented by a random number).

See the benchmarks to compare the 3 types.

Clock regressions of up to 10 seconds are handled to keep monotonicity.

Type 1 (default)

Type 1 uses method 1 of the specification to generate UUIDv7. This type is twice as fast as UUID.randomUUID().

UUID uuid = UuidCreator.getTimeOrderedEpoch();

Structure of the UUID v7:

  01720b5c-bf10-77cc-b631-4f262f500172
                ^^^^ ^^^^  <- plus 1

 |-------------|---------|------------|
       time      counter     random

Notes:
* The counter component is randomized when the time changes.
* The counter component is incremented by 1 when the time repeats.
* The random component is always randomized.

Sequence of UUID v7:

  0181be8a-e592-73d4-84fe-aaca0740fa1d
  0181be8a-e592-73d4-84ff-f59a5a4d9115
  0181be8a-e592-73d4-8500-d5affa859d31
  0181be8a-e592-73d4-8501-afb19130e7c4
  0181be8a-e592-73d4-8502-a802d8fa7689
  0181be8a-e592-73d4-8503-b712f3ca2caa
  0181be8a-e592-73d4-8504-09b220ad9b8c
  0181be8a-e592-73d4-8505-28cdc6fd9d64
  0181be8a-e593-7693-8890-3fd3dc34aeec  < millisecond changed
  0181be8a-e593-7693-8891-eab210bf4dba
  0181be8a-e593-7693-8892-a2fd10099b16
  0181be8a-e593-7693-8893-801739366152
  0181be8a-e593-7693-8894-de1f8c2f3f39
  0181be8a-e593-7693-8895-817d9bb344ef
  0181be8a-e593-7693-8896-b3cd2cffbebe
  0181be8a-e593-7693-8897-8dc4c8d2f4bd
              ^ look    ^ look

 |-------------|---------|------------|
       time      counter     random

Type 2 (plus 1)

Type 2 uses method 2 from spec to generate UUIDv7. The least significant bits are incremented by 1 when the time has not changed since the last generated UUIDv7. This type can be 20x faster than UUID.randomUUID().

UUID uuid = UuidCreator.getTimeOrderedEpochPlus1();

Structure of the UUID v7 with increments of 1:

  01720b5c-bf10-77cc-b631-4f262f500172
                ^^^^ ^^^^ ^^^^^^^^^^^^ <- plus 1

 |-------------|----------------------|
       time        monotonic random

Notes:
* The monotonic random component is randomized when the time changes.
* The monotonic random component incremented by 1 when the time repeats.

Sequence of UUID v7:

  0181be8a-e59a-73c8-b04c-06c9c7ab6d56
  0181be8a-e59a-73c8-b04c-06c9c7ab6d57
  0181be8a-e59a-73c8-b04c-06c9c7ab6d58
  0181be8a-e59a-73c8-b04c-06c9c7ab6d59
  0181be8a-e59a-73c8-b04c-06c9c7ab6d5a
  0181be8a-e59a-73c8-b04c-06c9c7ab6d5b
  0181be8a-e59a-73c8-b04c-06c9c7ab6d5c
  0181be8a-e59a-73c8-b04c-06c9c7ab6d5d
  0181be8a-e59b-7392-84bc-79c4faadcad8  < millisecond changed
  0181be8a-e59b-7392-84bc-79c4faadcad9
  0181be8a-e59b-7392-84bc-79c4faadcada
  0181be8a-e59b-7392-84bc-79c4faadcadb
  0181be8a-e59b-7392-84bc-79c4faadcadc
  0181be8a-e59b-7392-84bc-79c4faadcadd
  0181be8a-e59b-7392-84bc-79c4faadcade
  0181be8a-e59b-7392-84bc-79c4faadcadf
              ^ look                 ^ look

 |-------------|----------------------|
       time       monotonic random

Type 3 (plus n)

Type 3 uses method 2 from spec to generate UUID v7. The least significant bits are incremented by a random number when the time has not changed since the last generated UUIDv7. This type is at least twice as fast as UUID.randomUUID().

The random number has a maximum value of 2^32. However, a different maximum value can be specified for TimeOrderedEpochFactory if necessary. See the last example in next section.

UUID uuid = UuidCreator.getTimeOrderedEpochPlusN();

Structure of the UUID v7 with random increments:

  01720b5c-bf10-77cc-b631-4f262f500172
                ^^^^ ^^^^ ^^^^^^^^^^^^ <- plus n, where 1 <= n <= 2^32

 |-------------|----------------------|
       time        monotonic random    

* The monotonic random component is randomized when the time changes.
* The monotonic random component incremented by a positive integer `n` when the time repeats.
* The positive integer `n` maximum value can be specified via factory builder.
* The positive integer `n` is always randomized.

Sequence of UUID v7:

  0181be8a-e5ac-7cc0-a3e5-84ea795e8418
  0181be8a-e5ac-7cc0-a3e5-84eaceb743e7
  0181be8a-e5ac-7cc0-a3e5-84ebb3b9dbe7
  0181be8a-e5ac-7cc0-a3e5-84eca0e14876
  0181be8a-e5ac-7cc0-a3e5-84ed1fdc19c6
  0181be8a-e5ac-7cc0-a3e5-84ee082176d8
  0181be8a-e5ac-7cc0-a3e5-84ee1d1f63ae
  0181be8a-e5ac-7cc0-a3e5-84eeafd13b2a
  0181be8a-e5ad-790f-91a1-900fe2d661cc   < millisecond changed
  0181be8a-e5ad-790f-91a1-901051bb5f55
  0181be8a-e5ad-790f-91a1-90110ca4ebf6
  0181be8a-e5ad-790f-91a1-901119498fd6
  0181be8a-e5ad-790f-91a1-9011903ff6aa
  0181be8a-e5ad-790f-91a1-901215a742d8
  0181be8a-e5ad-790f-91a1-9012407c8742
  0181be8a-e5ad-790f-91a1-90127c104374
              ^ look         ^ look

 |-------------|----------------------|
       time       monotonic random

More examples

A key generator that makes substitution easy if necessary:

package com.example;

import com.github.f4b6a3.uuid.UuidCreator;

public class UuidGenerator {
    public static UUID generate() {
        return UuidCreator.getTimeOrderedEpoch();
    }
}
    UUID uuid = UuidGenerator.generate();

An UUID v7 factory with Random:

    // a UUID v7 factory with `Random`
    TimeOrderedEpochFactory factory = new TimeOrderedEpochFactory(new Random());
    // use the custom factory
    UUID uuid = factory.create();

A random-based factory with SplittableRandom:

    // use a random function that returns a long value
    SplittableRandom random = new SplittableRandom();
    TimeOrderedEpochFactory factory = new TimeOrderedEpochFactory(() -> random.nextLong());
    // use the factory
    UUID uuid = factory.create();

A random-based factory with RandomGenerator (JDK 17+):

    // use a random function that returns a long value
    RandomGenerator random = RandomGenerator.getDefault();
    TimeOrderedEpochFactory factory = new TimeOrderedEpochFactory(() -> random.nextLong());
    // use the factory
    UUID uuid = factory.create();

An UUID v7 factory with ThreadLocalRandom:

    // a UUID v7 factory with a custom `RandomFunction`
    TimeOrderedEpochFactory factory = new TimeOrderedEpochFactory((int length) -> {
        final byte[] bytes = new byte[length];
        ThreadLocalRandom.current().nextBytes(bytes);
        return bytes;
    });
    // use the custom factory
    UUID uuid = factory.create();

A UUID v7 factory with random increments:

    // maximum increment
    long maximum = 100_000;
    
    // a UUID v7 factory with random increments between 1 and 100,000
    TimeOrderedEpochFactory factory = TimeOrderedEpochFactory.builder() //
        .withIncrementPlusN(maximum).build();
    // use the custom factory
    UUID uuid = factory.create();
Clone this wiki locally