@@ -2,7 +2,6 @@ package uuid
22
33import (
44 "crypto/rand"
5- "encoding/binary"
65 "encoding/hex"
76 "errors"
87 "fmt"
@@ -24,8 +23,8 @@ type UUID [16]byte
2423// Nil represents the zero-value UUID
2524var Nil UUID
2625
27- // NewV4 returns a UUID Version 4 as defined in RFC9562. Random bits
28- // are generated using crypto/rand.
26+ // NewV4 returns a Version 4 UUID as defined in [ RFC9562] . Random bits
27+ // are generated using [ crypto/rand] .
2928//
3029// 0 1 2 3
3130// 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 6 7 8 9 0 1
@@ -38,6 +37,8 @@ var Nil UUID
3837// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3938// | random_c |
4039// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40+ //
41+ // [RFC9562]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
4142func NewV4 () (UUID , error ) {
4243 var uuid UUID
4344
@@ -53,11 +54,12 @@ func NewV4() (UUID, error) {
5354 return uuid , nil
5455}
5556
56- // NewV7 returns a UUID Version 7 as defined in the drafted revision for RFC9562.
57- // Random bits are generated using crypto/rand.
58- // Due to millisecond resolution of the timestamp, UUIDs generated during the
59- // same millisecond will sort arbitrarily.
60- // https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
57+ // NewV7 returns a Version 7 UUID as defined in [RFC9562].
58+ // Random bits are generated using [crypto/rand].
59+ //
60+ // This function employs method 3 (Replace Leftmost Random Bits with Increased Clock Precision)
61+ // to increase the clock precision of the UUID. This helps support scenarios where
62+ // several UUIDs are generated within the same millisecond.
6163//
6264// 0 1 2 3
6365// 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 6 7 8 9 0 1
@@ -70,15 +72,38 @@ func NewV4() (UUID, error) {
7072// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
7173// | rand_b |
7274// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75+ //
76+ // [RFC9562]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
7377func NewV7 () (UUID , error ) {
7478 var uuid UUID
7579
7680 t := time .Now ()
77- ms := t .UnixMilli () & ((1 << 48 ) - 1 ) // 48 bit timestamp
78- binary .BigEndian .PutUint64 (uuid [:], uint64 (ms << 16 )) // lower 48 bits. Right 0 padded
81+ ms := t .UnixMilli ()
82+
83+ // Extract each byte from the 48-bit timestamp
84+ uuid [0 ] = byte (ms >> 40 ) // Most significant byte
85+ uuid [1 ] = byte (ms >> 32 )
86+ uuid [2 ] = byte (ms >> 24 )
87+ uuid [3 ] = byte (ms >> 16 )
88+ uuid [4 ] = byte (ms >> 8 )
89+ uuid [5 ] = byte (ms ) // Least significant byte
90+
91+ // Calculate sub-millisecond precision for rand_a (12 bits)
92+ ns := t .UnixNano ()
93+
94+ // Calculate sub-millisecond precision by:
95+ // 1. Taking nanoseconds modulo 1 million to get just the sub-millisecond portion
96+ // 2. Multiply by 4096 (2^12) to scale to 12 bits of precision
97+ // 3. Divide by 1 million to normalize back to a 12-bit fraction
98+ // This provides monotonically increasing values within the same millisecond
99+ subMs := ((ns % 1_000_000 ) * (1 << 12 )) / 1_000_000
100+
101+ // Fill the increased clock precision into "rand_a" bits
102+ uuid [6 ] = byte (subMs >> 8 )
103+ uuid [7 ] = byte (subMs )
79104
80105 // Fill the rest with random data
81- _ , err := io .ReadFull (rand .Reader , uuid [6 :])
106+ _ , err := io .ReadFull (rand .Reader , uuid [8 :])
82107 if err != nil {
83108 return UUID {}, err
84109 }
0 commit comments