@@ -2,7 +2,6 @@ package uuid
2
2
3
3
import (
4
4
"crypto/rand"
5
- "encoding/binary"
6
5
"encoding/hex"
7
6
"errors"
8
7
"fmt"
@@ -24,8 +23,8 @@ type UUID [16]byte
24
23
// Nil represents the zero-value UUID
25
24
var Nil UUID
26
25
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] .
29
28
//
30
29
// 0 1 2 3
31
30
// 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
38
37
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39
38
// | random_c |
40
39
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40
+ //
41
+ // [RFC9562]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
41
42
func NewV4 () (UUID , error ) {
42
43
var uuid UUID
43
44
@@ -53,11 +54,12 @@ func NewV4() (UUID, error) {
53
54
return uuid , nil
54
55
}
55
56
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.
61
63
//
62
64
// 0 1 2 3
63
65
// 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) {
70
72
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71
73
// | rand_b |
72
74
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75
+ //
76
+ // [RFC9562]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7
73
77
func NewV7 () (UUID , error ) {
74
78
var uuid UUID
75
79
76
80
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 )
79
104
80
105
// Fill the rest with random data
81
- _ , err := io .ReadFull (rand .Reader , uuid [6 :])
106
+ _ , err := io .ReadFull (rand .Reader , uuid [8 :])
82
107
if err != nil {
83
108
return UUID {}, err
84
109
}
0 commit comments