|
FORUMS PROFESSIONNELS WINDEV, WEBDEV et WINDEV Mobile |
| | | | | |
| 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^ 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, + "-" + 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 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 ``` |
| |
| |
| | | |
|
| | | | |
| | |
| | |
| |
|
|
|