Pular para o conteúdo

Gerador de ULID - Crie IDs Únicos e Ordenáveis Online Gratuitamente

Ferramenta gratuita de geração de ULID cria identificadores únicos e ordenáveis instantaneamente. Gere ULIDs criptograficamente seguros para bancos de dados, APIs e sistemas distribuídos online.

Gerador de ULID

Insira um valor para ver os resultados
Calculadora de carregamento...
📚

Documentação

O que é um ULID?

Um ULID (Universally Unique Lexicographically Sortable Identifier, ou identificador único universal ordenável lexicograficamente) é um código de 26 caracteres usado para identificar registros em um banco de dados ou um evento em um sistema distribuído. Ele combina o horário atual com dados aleatórios, de modo que uma lista de ULIDs ordenada alfabeticamente fica ordenada pelo momento em que cada um foi criado. Um gerador de ULID é uma ferramenta que produz esses códigos.

Estrutura do ULID

Um ULID tem duas partes, escritas uma após a outra, sem separador:

  • Carimbo de data/hora (10 caracteres): o número de milissegundos desde 1 de janeiro de 1970 (a época Unix), armazenado como um inteiro de 48 bits.
  • Aleatoriedade (16 caracteres): 80 bits de dados aleatórios, incluídos para que dois ULIDs criados no mesmo milissegundo continuem quase certamente diferentes.

As duas partes são escritas com o alfabeto Base32 de Crockford: os dígitos 0-9 e as letras A-Z, menos as letras I, L, O e U. I e L podem ser confundidos com o dígito 1, e O com o dígito 0. O U fica de fora para evitar palavras obscenas por acaso. O resultado é uma cadeia curta, fácil de ler em voz alta e segura para colocar diretamente em uma URL.

Como calcular um ULID

Um gerador de ULID monta um identificador em três etapas.

  1. Ler o horário atual em milissegundos desde a época Unix. Esse é um número de 48 bits.
  2. Gerar 80 bits de dados aleatórios, normalmente a partir de um gerador de números aleatórios criptograficamente seguro, o que dá 10 bytes aleatórios.
  3. Codificar as duas partes separadamente com o alfabeto Base32 de Crockford: o carimbo de data/hora de 48 bits vira 10 caracteres, e o valor aleatório de 80 bits vira 16 caracteres. As duas cadeias codificadas são unidas para formar o ULID final de 26 caracteres.

A codificação funciona lendo o número 5 bits de cada vez, porque cada caractere Base32 representa um entre 32 valores possíveis (2^5 = 32). Dez caracteres comportam até 50 bits, o que é espaço suficiente para o carimbo de data/hora de 48 bits. Dezesseis caracteres comportam exatamente 80 bits, o que corresponde à parte aleatória sem sobra.

Exemplo resolvido

Suponha que um gerador de ULID seja executado no carimbo de data/hora 1712345678901 (milissegundos desde a época) e sorteie os bytes aleatórios [12, 240, 88, 3, 199, 45, 6, 231, 128, 17].

Etapa 1 – codificar o carimbo de data/hora. Divida 1712345678901 repetidamente por 32, tomando o resto a cada vez e lendo os dígitos do último ao primeiro (é a conversão de base padrão). Isso produz a cadeia de 10 caracteres 01HTQW311N.

Etapa 2 – codificar a parte aleatória. Agrupe os 10 bytes aleatórios em um fluxo de 80 bits e depois leia 5 bits de cada vez, convertendo cada bloco de 5 bits em um caractere Base32. Isso produz a cadeia de 16 caracteres 1KR5G0Y75M3EF00H.

Etapa 3 – unir as partes. O ULID final é:

101HTQW311N 1KR5G0Y75M3EF00H
2

escrito sem o espaço: 01HTQW311N1KR5G0Y75M3EF00H, 26 caracteres no total.

ULID e UUID

CaracterísticaULIDUUID (versão 4)
Comprimento26 caracteres36 caracteres (com hifens)
Ordenável pelo horário de criaçãoSimNão
CodificaçãoBase32 de CrockfordHexadecimal
Contém um carimbo de data/horaSim (48 bits)Não
Seguro para URL sem necessidade de escapeSimSim

Os dois formatos buscam produzir identificadores únicos entre sistemas, sem uma autoridade central que distribua os números. A principal diferença prática é a ordenação: como um ULID começa com um carimbo de data/hora, ordenar ULIDs como texto simples também os ordena por tempo. Um UUID aleatório não tem essa propriedade, pois todas as suas partes são aleatórias.

Usos comuns

  • Chaves primárias de banco de dados: os ULIDs permitem que um banco de dados indexe novas linhas aproximadamente na ordem em que foram inseridas, o que muitos mecanismos de banco de dados tratam com mais eficiência do que chaves totalmente aleatórias.
  • Sistemas distribuídos: servidores separados podem gerar ULIDs de forma independente, sem se coordenar com um contador central, e os resultados continuam quase certamente únicos.
  • Registros de eventos: como os ULIDs se ordenam por tempo, uma lista de IDs de eventos pode servir também como uma linha do tempo aproximada.
  • Identificadores de API e de arquivos: o formato fixo de 26 caracteres, seguro para URL, funciona bem em endereços web e nomes de arquivos.

Formatos de identificador relacionados incluem o KSUID, que também codifica um carimbo de data/hora para ordenação, e os Snowflake IDs, usados pelo Twitter e por outros, que combinam um carimbo de data/hora, um identificador de máquina e um contador.

Exemplos de código

Cada exemplo abaixo monta um ULID do mesmo modo que a especificação do ULID descreve: codificar o carimbo de data/hora de 48 bits como 10 caracteres Base32 de Crockford, codificar 80 bits de aleatoriedade como mais 16 e uni-los.

JavaScript

1const ENCODING_CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
2
3function encodeULID(time, randomBytes) {
4  // Timestamp: 48 bits -> 10 characters
5  let timestampStr = '';
6  let t = time;
7  for (let i = 0; i < 10; i++) {
8    timestampStr = ENCODING_CHARS[t % 32] + timestampStr;
9    t = Math.floor(t / 32);
10  }
11
12  // Randomness: 80 bits -> 16 characters
13  let result = timestampStr;
14  let bits = 0;
15  let bitCount = 0;
16  for (let i = 0; i < 10; i++) {
17    bits = (bits << 8) | randomBytes[i];
18    bitCount += 8;
19    while (bitCount >= 5) {
20      bitCount -= 5;
21      result += ENCODING_CHARS[(bits >> bitCount) & 0x1f];
22    }
23  }
24  return result;
25}
26
27function generateULID() {
28  const randomBytes = crypto.getRandomValues(new Uint8Array(10));
29  return encodeULID(Date.now(), randomBytes);
30}
31
32console.log(generateULID());
33

Python

1import os
2import time
3
4ENCODING_CHARS = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
5
6def encode_ulid(time_ms, random_bytes):
7    # Timestamp: 48 bits -> 10 characters
8    chars = []
9    t = time_ms
10    for _ in range(10):
11        chars.append(ENCODING_CHARS[t % 32])
12        t //= 32
13    timestamp_part = "".join(reversed(chars))
14
15    # Randomness: 80 bits -> 16 characters
16    bits = 0
17    bit_count = 0
18    random_part = []
19    for byte in random_bytes:
20        bits = (bits << 8) | byte
21        bit_count += 8
22        while bit_count >= 5:
23            bit_count -= 5
24            random_part.append(ENCODING_CHARS[(bits >> bit_count) & 0x1F])
25
26    return timestamp_part + "".join(random_part)
27
28def generate_ulid():
29    return encode_ulid(int(time.time() * 1000), os.urandom(10))
30
31print(generate_ulid())
32

Java

1import java.security.SecureRandom;
2import java.time.Instant;
3
4public class ULIDGenerator {
5    private static final SecureRandom random = new SecureRandom();
6    private static final char[] ENCODING_CHARS =
7        "0123456789ABCDEFGHJKMNPQRSTVWXYZ".toCharArray();
8
9    public static String generateULID() {
10        long timestamp = Instant.now().toEpochMilli();
11        byte[] randomBytes = new byte[10];
12        random.nextBytes(randomBytes);
13
14        // Timestamp: 48 bits -> 10 characters
15        char[] timestampChars = new char[10];
16        long t = timestamp;
17        for (int i = 9; i >= 0; i--) {
18            timestampChars[i] = ENCODING_CHARS[(int) (t % 32)];
19            t /= 32;
20        }
21
22        // Randomness: 80 bits -> 16 characters
23        StringBuilder result = new StringBuilder(new String(timestampChars));
24        long bits = 0;
25        int bitCount = 0;
26        for (byte b : randomBytes) {
27            bits = (bits << 8) | (b & 0xFF);
28            bitCount += 8;
29            while (bitCount >= 5) {
30                bitCount -= 5;
31                result.append(ENCODING_CHARS[(int) ((bits >> bitCount) & 0x1F)]);
32            }
33        }
34        return result.toString();
35    }
36
37    public static void main(String[] args) {
38        System.out.println(generateULID());
39    }
40}
41

Perguntas frequentes

Para que serve um ULID? Um ULID serve como identificador único de uma linha de banco de dados, de um recurso de API ou de um evento registrado, nos casos em que ordenar por data de criação também é útil.

Qual é o tamanho de um ULID? Um ULID tem sempre 26 caracteres: 10 para o carimbo de data/hora e 16 para a parte aleatória.

Que codificação um ULID usa? Um ULID usa o alfabeto Base32 de Crockford, formado pelos dígitos 0-9 e pelas letras A-Z, com I, L, O e U removidos para evitar leituras erradas e palavras indesejadas.

Qual é a diferença entre um ULID e um UUID? Um ULID se ordena pela data de criação e tem 26 caracteres. Um UUID aleatório (versão 4) não se ordena por tempo e tem 36 caracteres, contando os hifens.

Qual é a probabilidade de colisão entre dois ULIDs? Os 80 bits de aleatoriedade tornam as colisões extremamente improváveis. Seria preciso gerar cerca de 1,3 trilhão de ULIDs no mesmo milissegundo para chegar a 50% de chance de dois deles coincidirem.

É possível gerar ULIDs sem conexão com a internet? Sim. Um ULID só precisa do relógio local e de um gerador de números aleatórios, então pode ser criado totalmente offline.

Referências

  1. ULID project. Universally Unique Lexicographically Sortable Identifier. Especificação do ULID — carimbo de data/hora em milissegundos de 48 bits, 80 bits de aleatoriedade, forma padrão de 10 + 16 caracteres, alfabeto Base32 de Crockford.
  2. Douglas Crockford. Base 32. Base32 de Crockford — o alfabeto de 32 símbolos e por que I, L, O e U são excluídos.