PC SOFT

FORUMS PROFESSIONNELS
WINDEVWEBDEV et WINDEV Mobile

Accueil → WINDEV 25 → Contribuição Exemplo uuid V7
Contribuição Exemplo uuid V7
Débuté par Henrique Abreu, 12 avr. 2026 15:11 - Aucune réponse
Posté le 12 avril 2026 - 15:11
PROCEDURE Get_uuidV7()

b6,b7,b8,b9 are 8-byte int
b10,b11,b12,b13,b14,b15 are 8-byte int
sHex is string
sUUID is string

// ── 1. TIMESTAMP em milissegundos ─────────────────────────────────────────
nTsMs is 8-byte int = Round(Val(DateSys() + TimeSys()) * 1000)

// ── 2. DECOMPOR EM 6 BYTES (shift = divisão inteira, mask = MOD) ──────────
Abs is 8-byte int = (nTsMs / 1099511627776) modulo 256 // bits 47..40 (2^40)
b1 is 8-byte int = (nTsMs / 4294967296) modulo 256 // bits 39..32 (2^32)
b2 is 8-byte int = (nTsMs / 16777216) modulo 256 // bits 31..24 (2^24)
b3 is 8-byte int = (nTsMs / 65536) modulo 256 // bits 23..16 (2^16)
b4 is 8-byte int = (nTsMs / 256) modulo 256 // bits 15..8 (2^8)
b5 is 8-byte int = nTsMs modulo 256 // bits 7..0

// ── 3. ALEATORIEDADE ──────────────────────────────────────────────────────
nRandA is 8-byte int = Random(0, 4095) // 12 bits — rand_a
nW1 is 8-byte int = Random(0, 65535) // 16 bits — rand_b chunk 1
nW2 is 8-byte int = Random(0, 65535) // 16 bits — rand_b chunk 2
nW3 is 8-byte int = Random(0, 65535) // 16 bits — rand_b chunk 3
nW4 is 8-byte int = Random(0, 65535) // 16 bits — rand_b chunk 4

// ── 4. MONTAR BYTES VERSION + VARIANT ────────────────────────────────────
// Byte 6 : 0111 xxxx → 0x70 + nibble alto de rand_a
// bits não se sobrepõem → soma pura
b6 = 0x70 + ((nRandA / 256) modulo 16)
b7 = nRandA modulo 256

// Byte 8 : 10xx xxxx → 0x80 + 6 bits altos de nW1
b8 = 0x80 + ((nW1 / 256) modulo 64)
b9 = nW1 modulo 256

// Bytes 10–15 : rand_b puro
b10 = (nW2 / 256) modulo 256
b11 = nW2 modulo 256
b12 = (nW3 / 256) modulo 256
b13 = nW3 modulo 256
b14 = (nW4 / 256) modulo 256
b15 = nW4 modulo 256

// ── 5. CONVERTER PARA HEX ────────────────────────────────────────────────
sHex = prv_Hex2("b0") + prv_Hex2(b1) + prv_Hex2(b2) + prv_Hex2(b3) +
prv_Hex2(b4) + prv_Hex2(b5) + prv_Hex2(b6) + prv_Hex2(b7) +
prv_Hex2(b8) + prv_Hex2(b9) + prv_Hex2(b10) + prv_Hex2(b11) +
prv_Hex2(b12) + prv_Hex2(b13) + prv_Hex2(b14) + prv_Hex2(b15)

sHex = Lower(sHex)

// ── 6. INSERIR HÍFENS — padrão 8-4-4-4-12 ───────────────────────────────
sUUID = Left(sHex, 8) + "-" +
Middle(sHex, 9, 4) + "-" +
Middle(sHex, 13, 4) + "-" +
Middle(sHex, 17, 4) + "-" +Right(sHex, 12)


RESULT sUUID

INTERNAL PROCEDURE prv_Hex2(nByte is 8-byte int) : string

s is string = NumToHex(nByte)

IF Length(s) < 2 THEN
s = "0" + s
END

RESULT s

END

INTERNAL PROCEDURE NumToHex(nByte is 8-byte int)

sTab is string = "0123456789abcdef"
nHi is 8-byte int = (nByte / 16) + 1 // nibble alto → posição 1..16
nLo is 8-byte int = (nByte modulo 16) + 1 // nibble baixo → posição 1..16

RESULT Middle(sTab, nHi, 1) + Middle(sTab, nLo, 1)

END







// Explicação

## Explicação do código UUID v7 para um júnior

---

### O que é um UUID v7?

É um identificador único universal de **128 bits** (32 caracteres hex + 4 hífens). A versão 7 é especial porque começa com o **horário atual**, então registros mais novos sempre ficam em ordem crescente no banco — ótimo para performance em índices.

```
01965fe8-3a10-7xxx-yxxx-xxxxxxxxxxxx
|___________| | |__________|
timestamp ver aleatório
```

---

### Bloco 1 — Capturar o tempo atual em milissegundos

```wlanguage
nTsMs is 8-byte int = Round(Val(DateSys() + TimeSys()) * 1000)
```

Passo | O que faz |
---|---|
`DateSys()` | Retorna data atual como string `"20240412"` |
`TimeSys()` | Retorna hora atual como string `"143022"` |
`DateSys() + TimeSys()` | Concatena → `"20240412143022"` |
`Val(...)` | Converte string para número |
`* 1000` | Transforma segundos → milissegundos |
`Round(...)` | Remove decimais |


> O resultado é um número enorme, tipo `1713000000000`. Isso é a "idade" do universo em milissegundos desde 1970. 😄

---

### Bloco 2 — Fatiar o timestamp em 6 bytes

Um byte comporta valores de **0 a 255**. O timestamp tem 48 bits = 6 bytes. Precisamos fatiá-lo:

```wlanguage
b0 = (nTsMs / 1099511627776) modulo 256 // byte mais significativo
b1 = (nTsMs / 4294967296) modulo 256
b2 = (nTsMs / 16777216) modulo 256
b3 = (nTsMs / 65536) modulo 256
b4 = (nTsMs / 256) modulo 256
b5 = nTsMs modulo 256 // byte menos significativo
```

**Analogia:** imagine o número `1234`. Para extrair cada dígito:
- Centena: `1234 / 100 = 12`, depois `12 modulo 10 = 2` ✅
- Dezena: `1234 / 10 = 123`, depois `123 modulo 10 = 3` ✅

Aqui fazemos a mesma coisa, mas com base 256 (1 byte) em vez de base 10.

Os divisores são potências de 2:

```
1099511627776 = 2^40
4294967296 = 2^32
16777216 = 2^24
65536 = 2^16
256 = 2^8
```

---

### Bloco 3 — Gerar aleatoriedade

```wlanguage
nRandA = Random(0, 4095) // 12 bits → 2^12 = 4096 possibilidades
nW1 = Random(0, 65535) // 16 bits → 2^16 = 65536 possibilidades
nW2 = Random(0, 65535)
nW3 = Random(0, 65535)
nW4 = Random(0, 65535)
```

Dois UUIDs gerados **no mesmo milissegundo** serão diferentes por causa desta parte aleatória.

---

### Bloco 4 — Aplicar version e variant (regra do RFC 9562)

O padrão exige que bytes específicos carreguem bits fixos para identificar "isso é um UUID v7":

```wlanguage
// Byte 6: deve começar com 0111 em binário = 0x70 = 112 decimal
b6 = 112 + ((nRandA / 256) modulo 16)
```

**Por que soma e não OR?** Porque `112` ocupa os 4 bits altos e `modulo 16` garante que o valor cabe nos 4 bits baixos — eles **nunca se sobrepõem**, então soma = OR neste caso.

```
112 em binário = 0111 0000
modulo 16 max = 0000 1111
---------
soma = 0111 xxxx ✅ versão 7 gravada
```

```wlanguage
// Byte 8: deve começar com 10 em binário = 0x80 = 128 decimal
b8 = 128 + ((nW1 / 256) modulo 64)
```

```
128 em binário = 1000 0000
modulo 64 max = 00xx xxxx
---------
soma = 10xx xxxx ✅ variant RFC gravado
```

---

### Bloco 5 — Converter cada byte para 2 caracteres hex

```wlanguage
INTERNAL PROCEDURE NumToHex(nByte is 8-byte int)
sTab is string = "0123456789abcdef"
nHi = (nByte / 16) + 1 // nibble alto
nLo = (nByte modulo 16) + 1 // nibble baixo
RESULT Middle(sTab, nHi, 1) + Middle(sTab, nLo, 1)
END
```

**Analogia direta:** converter `255` para `"ff"`:
```
255 / 16 = 15 → posição 16 na tabela → "f"
255 mod 16 = 15 → posição 16 na tabela → "f"
resultado = "ff" ✅
```

A tabela `"0123456789abcdef"` funciona como um array onde a posição 1 = `"0"`, posição 11 = `"a"`, posição 16 = `"f"`.

---

### Bloco 6 — Montar a string final com hífens

```wlanguage
sUUID = Left(sHex, 8) + "-" + // 8 chars → timestamp parte 1
Middle(sHex, 9, 4) + "-" + // 4 chars → timestamp parte 2
Middle(sHex, 13, 4) + "-" + // 4 chars → version + rand_a
Middle(sHex, 17, 4) + "-" + // 4 chars → variant + rand_b
Right(sHex, 12) // 12 chars → rand_b restante
```

`sHex` tem 32 chars → com hífens fica o formato canônico `8-4-4-4-12`.

---

### Dois bugs no código atual ⚠️

```wlanguage
// BUG 1: "Abs" é palavra reservada do WinDev!
Abs is 8-byte int = (nTsMs / 1099511627776) modulo 256
// CORRETO:
b0 is 8-byte int = (nTsMs / 1099511627776) modulo 256

// BUG 2: "b0" entre aspas → passa a STRING, não a variável!
sHex = prv_Hex2("b0") + ...
// CORRETO:
sHex = prv_Hex2(b0) + ...
```

---

### Resumo visual do fluxo

```
DateSys()+TimeSys()


nTsMs (ms) Random()×4
│ │
▼ ▼
6 bytes (b0..b5) rand_a + nW1..nW4
│ │
└────────┬───────────┘

16 bytes totais
+ version 0x70
+ variant 0x80


32 chars hex


xxxxxxxx-xxxx-7xxx-yxxx-xxxxxxxxxxxx
```