RFR: 8334015: Add Support for UUID Version 7 (UUIDv7) defined in RFC 9562 [v16]

Jaikiran Pai jpai at openjdk.org
Tue Sep 30 06:05:55 UTC 2025


On Mon, 29 Sep 2025 15:08:14 GMT, Kieran Farrell <kfarrell at openjdk.org> wrote:

>> With the recent approval of UUIDv7 (https://datatracker.ietf.org/doc/rfc9562/), this PR aims to add a new static method UUID.timestampUUID() which constructs and returns a UUID in support of the new time generated UUID version. 
>> 
>> The specification requires embedding the current timestamp in milliseconds into the first bits 0–47. The version number in bits 48–51, bits 52–63 are available for sub-millisecond precision or for pseudorandom data. The variant is set in bits 64–65. The remaining bits 66–127 are free to use for more pseudorandom data or to employ a counter based approach for increased time percision (https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7).
>> 
>> The choice of implementation comes down to balancing the sensitivity level of being able to distingush UUIDs created below <1ms apart with performance. A test simulating a high-concurrency environment with 4 threads generating 10000 UUIDv7 values in parallel to measure the collision rate of each implementation (the amount of times the time based portion of the UUID was not unique and entries could not distinguished by time) yeilded the following results for each implemtation:
>> 
>> 
>> - random-byte-only - 99.8%
>> - higher-precision - 3.5%
>> - counter-based - 0%
>> 
>> 
>> Performance tests show a decrease in performance as expected with the counter based implementation due to the introduction of synchronization:
>> 
>> - random-byte-only   143.487 ± 10.932  ns/op
>> - higher-precision      149.651 ±  8.438 ns/op
>> - counter-based         245.036 ±  2.943  ns/op
>> 
>> The best balance here might be to employ a higher-precision implementation as the large increase in time sensitivity comes at a very slight performance cost.
>
> Kieran Farrell has updated the pull request incrementally with one additional commit since the last revision:
> 
>   missing semicolon

src/java.base/share/classes/java/util/UUID.java line 185:

> 183: 
> 184:     /**
> 185:      * Static factory to create a version 7 (time-based) {@code UUID} with a user-supplied

Would it be better to reword this method javadoc to something like:


/**
 * Creates a {@code UUIDv7} {@code UUID} from the given Unix Epoch timestamp.
 *
 * The returned {@code UUID} will have the given {@code timestamp} in
 * the first 6 bytes, followed by the version and variant bits representing {@code UUIDv7},
 * and the remaining bytes will contain random data from a cryptographically strong
 * pseudo-random number generator.
 *
 * @apiNote {@code UUIDv7} values are created by allocating a Unix timestamp in milliseconds
 * in the most significant 48 bits and filling the remaining 74 bits, excluding the required
 * version and variant bits, with random bits. As such, this method rejects {@code timestamp}
 * values that do not fit into 48 bits.
 *
 * @param timestamp the number of milliseconds since midnight 1 Jan 1970 UTC,
 *                 leap seconds excluded.
 *
 * @return a {@code UUID} constructed using the given {@code timestamp}
 *
 * @throws IllegalArgumentException if the timestamp is negative or greater than {@code 281474976710655L}
 *
 * @spec https://www.rfc-editor.org/rfc/rfc9562.html
 *       RFC 9562 Universally Unique IDentifiers (UUIDs)
 *
 * @since 26
 *
 */

(the text used for the apiNote is borrowed from the RFC)

src/java.base/share/classes/java/util/UUID.java line 207:

> 205:      *
> 206:      * @since 26
> 207:      * */

Nit - the `*/` should be on the next line.

src/java.base/share/classes/java/util/UUID.java line 208:

> 206:      * @since 26
> 207:      * */
> 208:     public static UUID epochMillis(long timestamp) {

Now that we have settled on which API to expose, would it be better to rename this new method to `fromEpochMillis(...)`? This class already has a `fromString(...)` API, so `fromEpochMillis(...)` would fit in with that style and would be a bit more precise too, I think.

src/java.base/share/classes/java/util/UUID.java line 210:

> 208:     public static UUID epochMillis(long timestamp) {
> 209:         if ((timestamp >> 48) != 0) {
> 210:             throw new IllegalArgumentException("Timestamp must be an unsigned 48-bit Unix Epoch time in milliseconds.");

Might be a good idea to include the passed `timestamp` value in the exception message to help identify what the incorrect value was. For example, maybe change the exception message to something like `"timestamp value " + timestamp + " exceeds 48 bits"`

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/25303#discussion_r2389949074
PR Review Comment: https://git.openjdk.org/jdk/pull/25303#discussion_r2389950223
PR Review Comment: https://git.openjdk.org/jdk/pull/25303#discussion_r2389954030
PR Review Comment: https://git.openjdk.org/jdk/pull/25303#discussion_r2389956994


More information about the core-libs-dev mailing list